blob: 69bcfa25cc4f11ba25a133b96d96e46b175ffa45 [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
Jeremy Hyltone3e61042001-05-09 15:50:25 +000013
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000014# XXX
15# Request
16# CacheFTPHandler (hard to write)
Thomas Wouters477c8d52006-05-27 19:21:47 +000017# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000018
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000019class TrivialTests(unittest.TestCase):
20 def test_trivial(self):
21 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000022
Jeremy Hylton1afc1692008-06-18 20:49:58 +000023 self.assertRaises(ValueError, urllib.request.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000024
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000025 # XXX Name hacking to get this to work on Windows.
Jeremy Hylton1afc1692008-06-18 20:49:58 +000026 fname = os.path.abspath(urllib.request.__file__).replace('\\', '/')
Senthil Kumarand587e302010-01-10 17:45:52 +000027
Senthil Kumarand587e302010-01-10 17:45:52 +000028 if os.name == 'nt':
29 file_url = "file:///%s" % fname
30 else:
31 file_url = "file://%s" % fname
32
Jeremy Hylton1afc1692008-06-18 20:49:58 +000033 f = urllib.request.urlopen(file_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000034
35 buf = f.read()
36 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000037
Georg Brandle1b13d22005-08-24 22:20:32 +000038 def test_parse_http_list(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000039 tests = [
40 ('a,b,c', ['a', 'b', 'c']),
41 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
42 ('a, b, "c", "d", "e,f", g, h',
43 ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
44 ('a="b\\"c", d="e\\,f", g="h\\\\i"',
45 ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
Georg Brandle1b13d22005-08-24 22:20:32 +000046 for string, list in tests:
Florent Xicluna419e3842010-08-08 16:16:07 +000047 self.assertEqual(urllib.request.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000048
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000049
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000050def test_request_headers_dict():
51 """
52 The Request.headers dictionary is not a documented interface. It should
53 stay that way, because the complete set of headers are only accessible
54 through the .get_header(), .has_header(), .header_items() interface.
55 However, .headers pre-dates those methods, and so real code will be using
56 the dictionary.
57
58 The introduction in 2.4 of those methods was a mistake for the same reason:
59 code that previously saw all (urllib2 user)-provided headers in .headers
60 now sees only a subset (and the function interface is ugly and incomplete).
61 A better change would have been to replace .headers dict with a dict
62 subclass (or UserDict.DictMixin instance?) that preserved the .headers
63 interface and also provided access to the "unredirected" headers. It's
64 probably too late to fix that, though.
65
66
67 Check .capitalize() case normalization:
68
69 >>> url = "http://example.com"
70 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
71 'blah'
72 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
73 'blah'
74
75 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
76 but that could be changed in future.
77
78 """
79
80def test_request_headers_methods():
81 """
82 Note the case normalization of header names here, to .capitalize()-case.
83 This should be preserved for backwards-compatibility. (In the HTTP case,
84 normalization to .title()-case is done by urllib2 before sending headers to
Georg Brandl24420152008-05-26 16:32:26 +000085 http.client).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000086
87 >>> url = "http://example.com"
88 >>> r = Request(url, headers={"Spam-eggs": "blah"})
89 >>> r.has_header("Spam-eggs")
90 True
91 >>> r.header_items()
92 [('Spam-eggs', 'blah')]
93 >>> r.add_header("Foo-Bar", "baz")
Guido van Rossumcc2b0162007-02-11 06:12:03 +000094 >>> items = sorted(r.header_items())
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000095 >>> items
96 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
97
98 Note that e.g. r.has_header("spam-EggS") is currently False, and
99 r.get_header("spam-EggS") returns None, but that could be changed in
100 future.
101
102 >>> r.has_header("Not-there")
103 False
Guido van Rossum7131f842007-02-09 20:13:25 +0000104 >>> print(r.get_header("Not-there"))
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000105 None
106 >>> r.get_header("Not-there", "default")
107 'default'
108
109 """
110
111
Thomas Wouters477c8d52006-05-27 19:21:47 +0000112def test_password_manager(self):
113 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000114 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000115 >>> add = mgr.add_password
116 >>> add("Some Realm", "http://example.com/", "joe", "password")
117 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
118 >>> add("c", "http://example.com/foo", "foo", "ni")
119 >>> add("c", "http://example.com/bar", "bar", "nini")
120 >>> add("b", "http://example.com/", "first", "blah")
121 >>> add("b", "http://example.com/", "second", "spam")
122 >>> add("a", "http://example.com", "1", "a")
123 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
124 >>> add("Some Realm", "d.example.com", "4", "d")
125 >>> add("Some Realm", "e.example.com:3128", "5", "e")
126
127 >>> mgr.find_user_password("Some Realm", "example.com")
128 ('joe', 'password')
129 >>> mgr.find_user_password("Some Realm", "http://example.com")
130 ('joe', 'password')
131 >>> mgr.find_user_password("Some Realm", "http://example.com/")
132 ('joe', 'password')
133 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
134 ('joe', 'password')
135 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
136 ('joe', 'password')
137 >>> mgr.find_user_password("c", "http://example.com/foo")
138 ('foo', 'ni')
139 >>> mgr.find_user_password("c", "http://example.com/bar")
140 ('bar', 'nini')
141
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000142 Actually, this is really undefined ATM
143## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000144
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000145## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
146## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000147
148 Use latest add_password() in case of conflict:
149
150 >>> mgr.find_user_password("b", "http://example.com/")
151 ('second', 'spam')
152
153 No special relationship between a.example.com and example.com:
154
155 >>> mgr.find_user_password("a", "http://example.com/")
156 ('1', 'a')
157 >>> mgr.find_user_password("a", "http://a.example.com/")
158 (None, None)
159
160 Ports:
161
162 >>> mgr.find_user_password("Some Realm", "c.example.com")
163 (None, None)
164 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
165 ('3', 'c')
166 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
167 ('3', 'c')
168 >>> mgr.find_user_password("Some Realm", "d.example.com")
169 ('4', 'd')
170 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
171 ('5', 'e')
172
173 """
174 pass
175
176
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000177def test_password_manager_default_port(self):
178 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000179 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000180 >>> add = mgr.add_password
181
182 The point to note here is that we can't guess the default port if there's
183 no scheme. This applies to both add_password and find_user_password.
184
185 >>> add("f", "http://g.example.com:80", "10", "j")
186 >>> add("g", "http://h.example.com", "11", "k")
187 >>> add("h", "i.example.com:80", "12", "l")
188 >>> add("i", "j.example.com", "13", "m")
189 >>> mgr.find_user_password("f", "g.example.com:100")
190 (None, None)
191 >>> mgr.find_user_password("f", "g.example.com:80")
192 ('10', 'j')
193 >>> mgr.find_user_password("f", "g.example.com")
194 (None, None)
195 >>> mgr.find_user_password("f", "http://g.example.com:100")
196 (None, None)
197 >>> mgr.find_user_password("f", "http://g.example.com:80")
198 ('10', 'j')
199 >>> mgr.find_user_password("f", "http://g.example.com")
200 ('10', 'j')
201 >>> mgr.find_user_password("g", "h.example.com")
202 ('11', 'k')
203 >>> mgr.find_user_password("g", "h.example.com:80")
204 ('11', 'k')
205 >>> mgr.find_user_password("g", "http://h.example.com:80")
206 ('11', 'k')
207 >>> mgr.find_user_password("h", "i.example.com")
208 (None, None)
209 >>> mgr.find_user_password("h", "i.example.com:80")
210 ('12', 'l')
211 >>> mgr.find_user_password("h", "http://i.example.com:80")
212 ('12', 'l')
213 >>> mgr.find_user_password("i", "j.example.com")
214 ('13', 'm')
215 >>> mgr.find_user_password("i", "j.example.com:80")
216 (None, None)
217 >>> mgr.find_user_password("i", "http://j.example.com")
218 ('13', 'm')
219 >>> mgr.find_user_password("i", "http://j.example.com:80")
220 (None, None)
221
222 """
223
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000224class MockOpener:
225 addheaders = []
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000226 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
227 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000228 def error(self, proto, *args):
229 self.proto, self.args = proto, args
230
231class MockFile:
232 def read(self, count=None): pass
233 def readline(self, count=None): pass
234 def close(self): pass
235
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000236class MockHeaders(dict):
237 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000238 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000239
Guido van Rossum34d19282007-08-09 01:03:29 +0000240class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000241 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000242 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000243 self.code, self.msg, self.headers, self.url = code, msg, headers, url
244 def info(self):
245 return self.headers
246 def geturl(self):
247 return self.url
248
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000249class MockCookieJar:
250 def add_cookie_header(self, request):
251 self.ach_req = request
252 def extract_cookies(self, response, request):
253 self.ec_req, self.ec_r = request, response
254
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000255class FakeMethod:
256 def __init__(self, meth_name, action, handle):
257 self.meth_name = meth_name
258 self.handle = handle
259 self.action = action
260 def __call__(self, *args):
261 return self.handle(self.meth_name, self.action, *args)
262
Senthil Kumaran47fff872009-12-20 07:10:31 +0000263class MockHTTPResponse(io.IOBase):
264 def __init__(self, fp, msg, status, reason):
265 self.fp = fp
266 self.msg = msg
267 self.status = status
268 self.reason = reason
269 self.code = 200
270
271 def read(self):
272 return ''
273
274 def info(self):
275 return {}
276
277 def geturl(self):
278 return self.url
279
280
281class MockHTTPClass:
282 def __init__(self):
283 self.level = 0
284 self.req_headers = []
285 self.data = None
286 self.raise_on_endheaders = False
287 self._tunnel_headers = {}
288
289 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
290 self.host = host
291 self.timeout = timeout
292 return self
293
294 def set_debuglevel(self, level):
295 self.level = level
296
297 def set_tunnel(self, host, port=None, headers=None):
298 self._tunnel_host = host
299 self._tunnel_port = port
300 if headers:
301 self._tunnel_headers = headers
302 else:
303 self._tunnel_headers.clear()
304
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000305 def request(self, method, url, body=None, headers=None):
Senthil Kumaran47fff872009-12-20 07:10:31 +0000306 self.method = method
307 self.selector = url
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000308 if headers is not None:
309 self.req_headers += headers.items()
Senthil Kumaran47fff872009-12-20 07:10:31 +0000310 self.req_headers.sort()
311 if body:
312 self.data = body
313 if self.raise_on_endheaders:
314 import socket
315 raise socket.error()
316 def getresponse(self):
317 return MockHTTPResponse(MockFile(), {}, 200, "OK")
318
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000319class MockHandler:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000320 # useful for testing handler machinery
321 # see add_ordered_mock_handlers() docstring
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000322 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000323 def __init__(self, methods):
324 self._define_methods(methods)
325 def _define_methods(self, methods):
326 for spec in methods:
327 if len(spec) == 2: name, action = spec
328 else: name, action = spec, None
329 meth = FakeMethod(name, action, self.handle)
330 setattr(self.__class__, name, meth)
331 def handle(self, fn_name, action, *args, **kwds):
332 self.parent.calls.append((self, fn_name, args, kwds))
333 if action is None:
334 return None
335 elif action == "return self":
336 return self
337 elif action == "return response":
338 res = MockResponse(200, "OK", {}, "")
339 return res
340 elif action == "return request":
341 return Request("http://blah/")
342 elif action.startswith("error"):
343 code = action[action.rfind(" ")+1:]
344 try:
345 code = int(code)
346 except ValueError:
347 pass
348 res = MockResponse(200, "OK", {}, "")
349 return self.parent.error("http", args[0], res, code, "", {})
350 elif action == "raise":
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000351 raise urllib.error.URLError("blah")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000352 assert False
353 def close(self): pass
354 def add_parent(self, parent):
355 self.parent = parent
356 self.parent.calls = []
357 def __lt__(self, other):
358 if not hasattr(other, "handler_order"):
359 # No handler_order, leave in original order. Yuck.
360 return True
361 return self.handler_order < other.handler_order
362
363def add_ordered_mock_handlers(opener, meth_spec):
364 """Create MockHandlers and add them to an OpenerDirector.
365
366 meth_spec: list of lists of tuples and strings defining methods to define
367 on handlers. eg:
368
369 [["http_error", "ftp_open"], ["http_open"]]
370
371 defines methods .http_error() and .ftp_open() on one handler, and
372 .http_open() on another. These methods just record their arguments and
373 return None. Using a tuple instead of a string causes the method to
374 perform some action (see MockHandler.handle()), eg:
375
376 [["http_error"], [("http_open", "return request")]]
377
378 defines .http_error() on one handler (which simply returns None), and
379 .http_open() on another handler, which returns a Request object.
380
381 """
382 handlers = []
383 count = 0
384 for meths in meth_spec:
385 class MockHandlerSubclass(MockHandler): pass
386 h = MockHandlerSubclass(meths)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000387 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000388 h.add_parent(opener)
389 count = count + 1
390 handlers.append(h)
391 opener.add_handler(h)
392 return handlers
393
Thomas Wouters477c8d52006-05-27 19:21:47 +0000394def build_test_opener(*handler_instances):
395 opener = OpenerDirector()
396 for h in handler_instances:
397 opener.add_handler(h)
398 return opener
399
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000400class MockHTTPHandler(urllib.request.BaseHandler):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000401 # useful for testing redirections and auth
402 # sends supplied headers and code as first response
403 # sends 200 OK as second response
404 def __init__(self, code, headers):
405 self.code = code
406 self.headers = headers
407 self.reset()
408 def reset(self):
409 self._count = 0
410 self.requests = []
411 def http_open(self, req):
Barry Warsaw820c1202008-06-12 04:06:45 +0000412 import email, http.client, copy
Guido van Rossum34d19282007-08-09 01:03:29 +0000413 from io import StringIO
Thomas Wouters477c8d52006-05-27 19:21:47 +0000414 self.requests.append(copy.deepcopy(req))
415 if self._count == 0:
416 self._count = self._count + 1
Georg Brandl24420152008-05-26 16:32:26 +0000417 name = http.client.responses[self.code]
Barry Warsaw820c1202008-06-12 04:06:45 +0000418 msg = email.message_from_string(self.headers)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000419 return self.parent.error(
420 "http", req, MockFile(), self.code, name, msg)
421 else:
422 self.req = req
Barry Warsaw820c1202008-06-12 04:06:45 +0000423 msg = email.message_from_string("\r\n\r\n")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000424 return MockResponse(200, "OK", msg, "", req.get_full_url())
425
Senthil Kumaran47fff872009-12-20 07:10:31 +0000426class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
427 # Useful for testing the Proxy-Authorization request by verifying the
428 # properties of httpcon
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000429
430 def __init__(self):
431 urllib.request.AbstractHTTPHandler.__init__(self)
432 self.httpconn = MockHTTPClass()
433
Senthil Kumaran47fff872009-12-20 07:10:31 +0000434 def https_open(self, req):
435 return self.do_open(self.httpconn, req)
436
Thomas Wouters477c8d52006-05-27 19:21:47 +0000437class MockPasswordManager:
438 def add_password(self, realm, uri, user, password):
439 self.realm = realm
440 self.url = uri
441 self.user = user
442 self.password = password
443 def find_user_password(self, realm, authuri):
444 self.target_realm = realm
445 self.target_url = authuri
446 return self.user, self.password
447
448
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000449class OpenerDirectorTests(unittest.TestCase):
450
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000451 def test_add_non_handler(self):
452 class NonHandler(object):
453 pass
454 self.assertRaises(TypeError,
455 OpenerDirector().add_handler, NonHandler())
456
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000457 def test_badly_named_methods(self):
458 # test work-around for three methods that accidentally follow the
459 # naming conventions for handler methods
460 # (*_open() / *_request() / *_response())
461
462 # These used to call the accidentally-named methods, causing a
463 # TypeError in real code; here, returning self from these mock
464 # methods would either cause no exception, or AttributeError.
465
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000466 from urllib.error import URLError
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000467
468 o = OpenerDirector()
469 meth_spec = [
470 [("do_open", "return self"), ("proxy_open", "return self")],
471 [("redirect_request", "return self")],
472 ]
473 handlers = add_ordered_mock_handlers(o, meth_spec)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000474 o.add_handler(urllib.request.UnknownHandler())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000475 for scheme in "do", "proxy", "redirect":
476 self.assertRaises(URLError, o.open, scheme+"://example.com/")
477
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000478 def test_handled(self):
479 # handler returning non-None means no more handlers will be called
480 o = OpenerDirector()
481 meth_spec = [
482 ["http_open", "ftp_open", "http_error_302"],
483 ["ftp_open"],
484 [("http_open", "return self")],
485 [("http_open", "return self")],
486 ]
487 handlers = add_ordered_mock_handlers(o, meth_spec)
488
489 req = Request("http://example.com/")
490 r = o.open(req)
491 # Second .http_open() gets called, third doesn't, since second returned
492 # non-None. Handlers without .http_open() never get any methods called
493 # on them.
494 # In fact, second mock handler defining .http_open() returns self
495 # (instead of response), which becomes the OpenerDirector's return
496 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000497 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000498 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
499 for expected, got in zip(calls, o.calls):
500 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000501 self.assertEqual((handler, name), expected)
502 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000503
504 def test_handler_order(self):
505 o = OpenerDirector()
506 handlers = []
507 for meths, handler_order in [
508 ([("http_open", "return self")], 500),
509 (["http_open"], 0),
510 ]:
511 class MockHandlerSubclass(MockHandler): pass
512 h = MockHandlerSubclass(meths)
513 h.handler_order = handler_order
514 handlers.append(h)
515 o.add_handler(h)
516
517 r = o.open("http://example.com/")
518 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000519 self.assertEqual(o.calls[0][0], handlers[1])
520 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000521
522 def test_raise(self):
523 # raising URLError stops processing of request
524 o = OpenerDirector()
525 meth_spec = [
526 [("http_open", "raise")],
527 [("http_open", "return self")],
528 ]
529 handlers = add_ordered_mock_handlers(o, meth_spec)
530
531 req = Request("http://example.com/")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000532 self.assertRaises(urllib.error.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000533 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000534
535## def test_error(self):
536## # XXX this doesn't actually seem to be used in standard library,
537## # but should really be tested anyway...
538
539 def test_http_error(self):
540 # XXX http_error_default
541 # http errors are a special case
542 o = OpenerDirector()
543 meth_spec = [
544 [("http_open", "error 302")],
545 [("http_error_400", "raise"), "http_open"],
546 [("http_error_302", "return response"), "http_error_303",
547 "http_error"],
548 [("http_error_302")],
549 ]
550 handlers = add_ordered_mock_handlers(o, meth_spec)
551
552 class Unknown:
553 def __eq__(self, other): return True
554
555 req = Request("http://example.com/")
556 r = o.open(req)
557 assert len(o.calls) == 2
558 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000559 (handlers[2], "http_error_302",
560 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000561 for expected, got in zip(calls, o.calls):
562 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000563 self.assertEqual((handler, method_name), got[:2])
564 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000565
566 def test_processors(self):
567 # *_request / *_response methods get called appropriately
568 o = OpenerDirector()
569 meth_spec = [
570 [("http_request", "return request"),
571 ("http_response", "return response")],
572 [("http_request", "return request"),
573 ("http_response", "return response")],
574 ]
575 handlers = add_ordered_mock_handlers(o, meth_spec)
576
577 req = Request("http://example.com/")
578 r = o.open(req)
579 # processor methods are called on *all* handlers that define them,
580 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000581 calls = [
582 (handlers[0], "http_request"), (handlers[1], "http_request"),
583 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000584
585 for i, (handler, name, args, kwds) in enumerate(o.calls):
586 if i < 2:
587 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000588 self.assertEqual((handler, name), calls[i])
589 self.assertEqual(len(args), 1)
Ezio Melottie9615932010-01-24 19:26:24 +0000590 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000591 else:
592 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000593 self.assertEqual((handler, name), calls[i])
594 self.assertEqual(len(args), 2)
Ezio Melottie9615932010-01-24 19:26:24 +0000595 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000596 # response from opener.open is None, because there's no
597 # handler that defines http_open to handle it
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000598 self.assertTrue(args[1] is None or
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000599 isinstance(args[1], MockResponse))
600
601
Tim Peters58eb11c2004-01-18 20:29:55 +0000602def sanepathname2url(path):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000603 try:
604 path.encode("utf8")
605 except UnicodeEncodeError:
606 raise unittest.SkipTest("path is not encodable to utf8")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000607 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000608 if os.name == "nt" and urlpath.startswith("///"):
609 urlpath = urlpath[2:]
610 # XXX don't ask me about the mac...
611 return urlpath
612
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000613class HandlerTests(unittest.TestCase):
614
615 def test_ftp(self):
616 class MockFTPWrapper:
617 def __init__(self, data): self.data = data
618 def retrfile(self, filename, filetype):
619 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000620 return io.StringIO(self.data), len(self.data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000621
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000622 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000623 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000624 def connect_ftp(self, user, passwd, host, port, dirs,
625 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000626 self.user, self.passwd = user, passwd
627 self.host, self.port = host, port
628 self.dirs = dirs
629 self.ftpwrapper = MockFTPWrapper(self.data)
630 return self.ftpwrapper
631
Georg Brandlf78e02b2008-06-10 17:40:04 +0000632 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000633 data = "rheum rhaponicum"
634 h = NullFTPHandler(data)
635 o = h.parent = MockOpener()
636
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000637 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000638 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000639 "localhost", ftplib.FTP_PORT, "", "", "I",
640 ["foo", "bar"], "baz.html", "text/html"),
641 ("ftp://parrot@localhost/foo/bar/baz.html",
642 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
643 ["foo", "bar"], "baz.html", "text/html"),
644 ("ftp://%25parrot@localhost/foo/bar/baz.html",
645 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
646 ["foo", "bar"], "baz.html", "text/html"),
647 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
648 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000649 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000650 ("ftp://localhost:80/foo/bar/",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000651 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000652 ["foo", "bar"], "", None),
653 ("ftp://localhost/baz.gif;type=a",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000654 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000655 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000656 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000657 req = Request(url)
658 req.timeout = None
659 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000660 # ftp authentication not yet implemented by FTPHandler
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000661 self.assertEqual(h.user, user)
662 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000663 self.assertEqual(h.host, socket.gethostbyname(host))
664 self.assertEqual(h.port, port)
665 self.assertEqual(h.dirs, dirs)
666 self.assertEqual(h.ftpwrapper.filename, filename)
667 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000668 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000669 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000670 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000671
672 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000673 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000674 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000675 o = h.parent = MockOpener()
676
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000677 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000678 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000679 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000680 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000681 "file://localhost%s" % urlpath,
682 "file://%s" % urlpath,
683 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000684 ]
685 try:
686 localaddr = socket.gethostbyname(socket.gethostname())
687 except socket.gaierror:
688 localaddr = ''
689 if localaddr:
690 urls.append("file://%s%s" % (localaddr, urlpath))
691
692 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000693 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000694 try:
695 try:
696 f.write(towrite)
697 finally:
698 f.close()
699
700 r = h.file_open(Request(url))
701 try:
702 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000703 headers = r.info()
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000704 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000705 finally:
706 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000707 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000708 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000709 finally:
710 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000711 self.assertEqual(data, towrite)
712 self.assertEqual(headers["Content-type"], "text/plain")
713 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000714 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000715 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000716
717 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000718 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000719 "file:///file_does_not_exist.txt",
720 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
721 os.getcwd(), TESTFN),
722 "file://somerandomhost.ontheinternet.com%s/%s" %
723 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000724 ]:
725 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000726 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000727 try:
728 f.write(towrite)
729 finally:
730 f.close()
731
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000732 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000733 h.file_open, Request(url))
734 finally:
735 os.remove(TESTFN)
736
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000737 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000738 o = h.parent = MockOpener()
739 # XXXX why does // mean ftp (and /// mean not ftp!), and where
740 # is file: scheme specified? I think this is really a bug, and
741 # what was intended was to distinguish between URLs like:
742 # file:/blah.txt (a file)
743 # file://localhost/blah.txt (a file)
744 # file:///blah.txt (a file)
745 # file://ftp.example.com/blah.txt (an ftp URL)
746 for url, ftp in [
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000747 ("file://ftp.example.com//foo.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000748 ("file://ftp.example.com///foo.txt", False),
749# XXXX bug: fails with OSError, should be URLError
750 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000751 ("file://somehost//foo/something.txt", False),
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000752 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000753 ]:
754 req = Request(url)
755 try:
756 h.file_open(req)
757 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000758 except (urllib.error.URLError, OSError):
Florent Xicluna419e3842010-08-08 16:16:07 +0000759 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000760 else:
Florent Xicluna419e3842010-08-08 16:16:07 +0000761 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000762 self.assertEqual(req.type, "ftp")
Łukasz Langad7e81cc2011-01-09 18:18:53 +0000763 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000764
765 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000766
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000767 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000768 o = h.parent = MockOpener()
769
770 url = "http://example.com/"
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000771 for method, data in [("GET", None), ("POST", b"blah")]:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000772 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000773 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000774 req.add_unredirected_header("Spam", "eggs")
775 http = MockHTTPClass()
776 r = h.do_open(http, req)
777
778 # result attributes
779 r.read; r.readline # wrapped MockFile methods
780 r.info; r.geturl # addinfourl methods
781 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
782 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000783 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000784 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000785
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000786 self.assertEqual(http.host, "example.com")
787 self.assertEqual(http.level, 0)
788 self.assertEqual(http.method, method)
789 self.assertEqual(http.selector, "/")
790 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000791 [("Connection", "close"),
792 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000793 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000794
795 # check socket.error converted to URLError
796 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000797 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000798
Senthil Kumaran29333122011-02-11 11:25:47 +0000799 # Check for TypeError on POST data which is str.
800 req = Request("http://example.com/","badpost")
801 self.assertRaises(TypeError, h.do_request_, req)
802
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000803 # check adding of standard headers
804 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000805 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000806 req = Request("http://example.com/", data)
807 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000808 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000809 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000810 self.assertNotIn("Content-length", req.unredirected_hdrs)
811 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000812 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000813 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
814 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000815 "application/x-www-form-urlencoded")
816 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000817 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
818 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000819
820 # don't clobber existing headers
821 req.add_unredirected_header("Content-length", "foo")
822 req.add_unredirected_header("Content-type", "bar")
823 req.add_unredirected_header("Host", "baz")
824 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000825 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000826 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
827 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000828 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
829 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000830
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000831 # Check iterable body support
832 def iterable_body():
833 yield b"one"
834 yield b"two"
835 yield b"three"
836
837 for headers in {}, {"Content-Length": 11}:
838 req = Request("http://example.com/", iterable_body(), headers)
839 if not headers:
840 # Having an iterable body without a Content-Length should
841 # raise an exception
842 self.assertRaises(ValueError, h.do_request_, req)
843 else:
844 newreq = h.do_request_(req)
845
Senthil Kumaran29333122011-02-11 11:25:47 +0000846 # A file object.
847 # Test only Content-Length attribute of request.
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000848
Senthil Kumaran29333122011-02-11 11:25:47 +0000849 file_obj = io.BytesIO()
850 file_obj.write(b"Something\nSomething\nSomething\n")
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000851
852 for headers in {}, {"Content-Length": 30}:
853 req = Request("http://example.com/", file_obj, headers)
854 if not headers:
855 # Having an iterable body without a Content-Length should
856 # raise an exception
857 self.assertRaises(ValueError, h.do_request_, req)
858 else:
859 newreq = h.do_request_(req)
860 self.assertEqual(int(newreq.get_header('Content-length')),30)
861
862 file_obj.close()
863
864 # array.array Iterable - Content Length is calculated
865
866 iterable_array = array.array("I",[1,2,3,4])
867
868 for headers in {}, {"Content-Length": 16}:
869 req = Request("http://example.com/", iterable_array, headers)
870 newreq = h.do_request_(req)
871 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000872
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000873 def test_http_doubleslash(self):
874 # Checks the presence of any unnecessary double slash in url does not
875 # break anything. Previously, a double slash directly after the host
876 # could could cause incorrect parsing.
877 h = urllib.request.AbstractHTTPHandler()
878 o = h.parent = MockOpener()
879
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000880 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000881 ds_urls = [
882 "http://example.com/foo/bar/baz.html",
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 ]
887
888 for ds_url in ds_urls:
889 ds_req = Request(ds_url, data)
890
891 # Check whether host is determined correctly if there is no proxy
892 np_ds_req = h.do_request_(ds_req)
893 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
894
895 # Check whether host is determined correctly if there is a proxy
896 ds_req.set_proxy("someproxy:3128",None)
897 p_ds_req = h.do_request_(ds_req)
898 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
899
Senthil Kumaranc2958622010-11-22 04:48:26 +0000900 def test_fixpath_in_weirdurls(self):
901 # Issue4493: urllib2 to supply '/' when to urls where path does not
902 # start with'/'
903
904 h = urllib.request.AbstractHTTPHandler()
905 o = h.parent = MockOpener()
906
907 weird_url = 'http://www.python.org?getspam'
908 req = Request(weird_url)
909 newreq = h.do_request_(req)
910 self.assertEqual(newreq.host,'www.python.org')
911 self.assertEqual(newreq.selector,'/?getspam')
912
913 url_without_path = 'http://www.python.org'
914 req = Request(url_without_path)
915 newreq = h.do_request_(req)
916 self.assertEqual(newreq.host,'www.python.org')
917 self.assertEqual(newreq.selector,'')
918
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000919
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000920 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000921 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000922 o = h.parent = MockOpener()
923
924 url = "http://example.com/"
925 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000926 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000927 r = MockResponse(200, "OK", {}, "", url)
928 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000929 self.assertIs(r, newr)
930 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000931 r = MockResponse(202, "Accepted", {}, "", url)
932 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000933 self.assertIs(r, newr)
934 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000935 r = MockResponse(206, "Partial content", {}, "", url)
936 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000937 self.assertIs(r, newr)
938 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000939 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000940 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000941 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000942 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000943 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000944
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000945 def test_cookies(self):
946 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000947 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000948 o = h.parent = MockOpener()
949
950 req = Request("http://example.com/")
951 r = MockResponse(200, "OK", {}, "")
952 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000953 self.assertIs(cj.ach_req, req)
954 self.assertIs(cj.ach_req, newreq)
955 self.assertEqual(req.get_origin_req_host(), "example.com")
956 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000957 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000958 self.assertIs(cj.ec_req, req)
959 self.assertIs(cj.ec_r, r)
960 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000961
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000962 def test_redirect(self):
963 from_url = "http://example.com/a.html"
964 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000965 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000966 o = h.parent = MockOpener()
967
968 # ordinary redirect behaviour
969 for code in 301, 302, 303, 307:
970 for data in None, "blah\nblah\n":
971 method = getattr(h, "http_error_%s" % code)
972 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000973 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000974 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000975 if data is not None:
976 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000977 req.add_unredirected_header("Spam", "spam")
978 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000979 method(req, MockFile(), code, "Blah",
980 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000981 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000982 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000983 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000984 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000985 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000986 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000987 except AttributeError:
Florent Xicluna419e3842010-08-08 16:16:07 +0000988 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +0000989
990 # now it's a GET, there should not be headers regarding content
991 # (possibly dragged from before being a POST)
992 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +0000993 self.assertNotIn("content-length", headers)
994 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +0000995
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000996 self.assertEqual(o.req.headers["Nonsense"],
997 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +0000998 self.assertNotIn("Spam", o.req.headers)
999 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001000
1001 # loop detection
1002 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001003 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001004 def redirect(h, req, url=to_url):
1005 h.http_error_302(req, MockFile(), 302, "Blah",
1006 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001007 # Note that the *original* request shares the same record of
1008 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001009
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001010 # detect infinite loop redirect of a URL to itself
1011 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001012 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001013 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001014 try:
1015 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001016 redirect(h, req, "http://example.com/")
1017 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001018 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001019 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001020 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001021
1022 # detect endless non-repeating chain of redirects
1023 req = Request(from_url, origin_req_host="example.com")
1024 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001025 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001026 try:
1027 while 1:
1028 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001029 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001030 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001031 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001032 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001033
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001034 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001035 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001036 from http.cookiejar import CookieJar
1037 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001038
1039 cj = CookieJar()
1040 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001041 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001042 hdeh = urllib.request.HTTPDefaultErrorHandler()
1043 hrh = urllib.request.HTTPRedirectHandler()
1044 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001045 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001046 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001047 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001048
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001049 def test_proxy(self):
1050 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001051 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001052 o.add_handler(ph)
1053 meth_spec = [
1054 [("http_open", "return response")]
1055 ]
1056 handlers = add_ordered_mock_handlers(o, meth_spec)
1057
1058 req = Request("http://acme.example.com/")
1059 self.assertEqual(req.get_host(), "acme.example.com")
1060 r = o.open(req)
1061 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1062
1063 self.assertEqual([(handlers[0], "http_open")],
1064 [tup[0:2] for tup in o.calls])
1065
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001066 def test_proxy_no_proxy(self):
1067 os.environ['no_proxy'] = 'python.org'
1068 o = OpenerDirector()
1069 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1070 o.add_handler(ph)
1071 req = Request("http://www.perl.org/")
1072 self.assertEqual(req.get_host(), "www.perl.org")
1073 r = o.open(req)
1074 self.assertEqual(req.get_host(), "proxy.example.com")
1075 req = Request("http://www.python.org")
1076 self.assertEqual(req.get_host(), "www.python.org")
1077 r = o.open(req)
1078 self.assertEqual(req.get_host(), "www.python.org")
1079 del os.environ['no_proxy']
1080
Ronald Oussorene72e1612011-03-14 18:15:25 -04001081 def test_proxy_no_proxy_all(self):
1082 os.environ['no_proxy'] = '*'
1083 o = OpenerDirector()
1084 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1085 o.add_handler(ph)
1086 req = Request("http://www.python.org")
1087 self.assertEqual(req.get_host(), "www.python.org")
1088 r = o.open(req)
1089 self.assertEqual(req.get_host(), "www.python.org")
1090 del os.environ['no_proxy']
1091
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001092
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001093 def test_proxy_https(self):
1094 o = OpenerDirector()
1095 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1096 o.add_handler(ph)
1097 meth_spec = [
1098 [("https_open", "return response")]
1099 ]
1100 handlers = add_ordered_mock_handlers(o, meth_spec)
1101
1102 req = Request("https://www.example.com/")
1103 self.assertEqual(req.get_host(), "www.example.com")
1104 r = o.open(req)
1105 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1106 self.assertEqual([(handlers[0], "https_open")],
1107 [tup[0:2] for tup in o.calls])
1108
Senthil Kumaran47fff872009-12-20 07:10:31 +00001109 def test_proxy_https_proxy_authorization(self):
1110 o = OpenerDirector()
1111 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1112 o.add_handler(ph)
1113 https_handler = MockHTTPSHandler()
1114 o.add_handler(https_handler)
1115 req = Request("https://www.example.com/")
1116 req.add_header("Proxy-Authorization","FooBar")
1117 req.add_header("User-Agent","Grail")
1118 self.assertEqual(req.get_host(), "www.example.com")
1119 self.assertIsNone(req._tunnel_host)
1120 r = o.open(req)
1121 # Verify Proxy-Authorization gets tunneled to request.
1122 # httpsconn req_headers do not have the Proxy-Authorization header but
1123 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001124 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001125 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001126 self.assertIn(("User-Agent","Grail"),
1127 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001128 self.assertIsNotNone(req._tunnel_host)
1129 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1130 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001131
Ronald Oussorene72e1612011-03-14 18:15:25 -04001132 def test_osx_proxy_bypass(self):
1133 bypass = {
1134 'exclude_simple': False,
1135 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1136 '10.0/16']
1137 }
1138 # Check hosts that should trigger the proxy bypass
1139 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1140 '10.0.0.1'):
1141 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1142 'expected bypass of %s to be True' % host)
1143 # Check hosts that should not trigger the proxy bypass
1144 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1145 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1146 'expected bypass of %s to be False' % host)
1147
1148 # Check the exclude_simple flag
1149 bypass = {'exclude_simple': True, 'exceptions': []}
1150 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1151
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001152 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001153 opener = OpenerDirector()
1154 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001155 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001156 realm = "ACME Widget Store"
1157 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001158 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1159 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001160 opener.add_handler(auth_handler)
1161 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001162 self._test_basic_auth(opener, auth_handler, "Authorization",
1163 realm, http_handler, password_manager,
1164 "http://acme.example.com/protected",
1165 "http://acme.example.com/protected",
1166 )
1167
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001168 def test_basic_auth_with_single_quoted_realm(self):
1169 self.test_basic_auth(quote_char="'")
1170
Thomas Wouters477c8d52006-05-27 19:21:47 +00001171 def test_proxy_basic_auth(self):
1172 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001173 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001174 opener.add_handler(ph)
1175 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001176 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001177 realm = "ACME Networks"
1178 http_handler = MockHTTPHandler(
1179 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001180 opener.add_handler(auth_handler)
1181 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001182 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001183 realm, http_handler, password_manager,
1184 "http://acme.example.com:3128/protected",
1185 "proxy.example.com:3128",
1186 )
1187
1188 def test_basic_and_digest_auth_handlers(self):
1189 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1190 # response (http://python.org/sf/1479302), where it should instead
1191 # return None to allow another handler (especially
1192 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001193
1194 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1195 # try digest first (since it's the strongest auth scheme), so we record
1196 # order of calls here to check digest comes first:
1197 class RecordingOpenerDirector(OpenerDirector):
1198 def __init__(self):
1199 OpenerDirector.__init__(self)
1200 self.recorded = []
1201 def record(self, info):
1202 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001203 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001204 def http_error_401(self, *args, **kwds):
1205 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001206 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001207 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001208 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001209 def http_error_401(self, *args, **kwds):
1210 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001211 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001212 *args, **kwds)
1213
1214 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001215 password_manager = MockPasswordManager()
1216 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001217 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001218 realm = "ACME Networks"
1219 http_handler = MockHTTPHandler(
1220 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001221 opener.add_handler(basic_handler)
1222 opener.add_handler(digest_handler)
1223 opener.add_handler(http_handler)
1224
1225 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001226 self._test_basic_auth(opener, basic_handler, "Authorization",
1227 realm, http_handler, password_manager,
1228 "http://acme.example.com/protected",
1229 "http://acme.example.com/protected",
1230 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001231 # check digest was tried before basic (twice, because
1232 # _test_basic_auth called .open() twice)
1233 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001234
1235 def _test_basic_auth(self, opener, auth_handler, auth_header,
1236 realm, http_handler, password_manager,
1237 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001238 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001239 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001240
1241 # .add_password() fed through to password manager
1242 auth_handler.add_password(realm, request_url, user, password)
1243 self.assertEqual(realm, password_manager.realm)
1244 self.assertEqual(request_url, password_manager.url)
1245 self.assertEqual(user, password_manager.user)
1246 self.assertEqual(password, password_manager.password)
1247
1248 r = opener.open(request_url)
1249
1250 # should have asked the password manager for the username/password
1251 self.assertEqual(password_manager.target_realm, realm)
1252 self.assertEqual(password_manager.target_url, protected_url)
1253
1254 # expect one request without authorization, then one with
1255 self.assertEqual(len(http_handler.requests), 2)
1256 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001257 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001258 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001259 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001260 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1261 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001262 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1263 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001264 # if the password manager can't find a password, the handler won't
1265 # handle the HTTP auth error
1266 password_manager.user = password_manager.password = None
1267 http_handler.reset()
1268 r = opener.open(request_url)
1269 self.assertEqual(len(http_handler.requests), 1)
1270 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1271
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001272class MiscTests(unittest.TestCase):
1273
1274 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001275 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1276 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001277 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001278 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001279 def bar_open(self): pass
1280
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001281 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001282
1283 o = build_opener(FooHandler, BarHandler)
1284 self.opener_has_handler(o, FooHandler)
1285 self.opener_has_handler(o, BarHandler)
1286
1287 # can take a mix of classes and instances
1288 o = build_opener(FooHandler, BarHandler())
1289 self.opener_has_handler(o, FooHandler)
1290 self.opener_has_handler(o, BarHandler)
1291
1292 # subclasses of default handlers override default handlers
1293 o = build_opener(MyHTTPHandler)
1294 self.opener_has_handler(o, MyHTTPHandler)
1295
1296 # a particular case of overriding: default handlers can be passed
1297 # in explicitly
1298 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001299 self.opener_has_handler(o, urllib.request.HTTPHandler)
1300 o = build_opener(urllib.request.HTTPHandler)
1301 self.opener_has_handler(o, urllib.request.HTTPHandler)
1302 o = build_opener(urllib.request.HTTPHandler())
1303 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001304
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001305 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001306 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001307 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1308 self.opener_has_handler(o, MyHTTPHandler)
1309 self.opener_has_handler(o, MyOtherHTTPHandler)
1310
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001311 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001312 self.assertTrue(any(h.__class__ == handler_class
1313 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001314
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001315class RequestTests(unittest.TestCase):
1316
1317 def setUp(self):
1318 self.get = Request("http://www.python.org/~jeremy/")
1319 self.post = Request("http://www.python.org/~jeremy/",
1320 "data",
1321 headers={"X-Test": "test"})
1322
1323 def test_method(self):
1324 self.assertEqual("POST", self.post.get_method())
1325 self.assertEqual("GET", self.get.get_method())
1326
1327 def test_add_data(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001328 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001329 self.assertEqual("GET", self.get.get_method())
1330 self.get.add_data("spam")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001331 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001332 self.assertEqual("POST", self.get.get_method())
1333
1334 def test_get_full_url(self):
1335 self.assertEqual("http://www.python.org/~jeremy/",
1336 self.get.get_full_url())
1337
1338 def test_selector(self):
1339 self.assertEqual("/~jeremy/", self.get.get_selector())
1340 req = Request("http://www.python.org/")
1341 self.assertEqual("/", req.get_selector())
1342
1343 def test_get_type(self):
1344 self.assertEqual("http", self.get.get_type())
1345
1346 def test_get_host(self):
1347 self.assertEqual("www.python.org", self.get.get_host())
1348
1349 def test_get_host_unquote(self):
1350 req = Request("http://www.%70ython.org/")
1351 self.assertEqual("www.python.org", req.get_host())
1352
1353 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001354 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001355 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001356 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001357 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1358 self.assertEqual("www.perl.org", self.get.get_host())
1359
Senthil Kumarand95cc752010-08-08 11:27:53 +00001360 def test_wrapped_url(self):
1361 req = Request("<URL:http://www.python.org>")
1362 self.assertEqual("www.python.org", req.get_host())
1363
1364 def test_urlwith_fragment(self):
1365 req = Request("http://www.python.org/?qs=query#fragment=true")
1366 self.assertEqual("/?qs=query", req.get_selector())
1367 req = Request("http://www.python.org/#fun=true")
1368 self.assertEqual("/", req.get_selector())
1369
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001370
1371def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001372 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001373 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001374 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001375 tests = (TrivialTests,
1376 OpenerDirectorTests,
1377 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001378 MiscTests,
1379 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001380 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001381
1382if __name__ == "__main__":
1383 test_main(verbose=True)