blob: 62226b834ce0190f0100fb096cad5522bf592163 [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
Jeremy Hyltone3e61042001-05-09 15:50:25 +00007
Jeremy Hylton1afc1692008-06-18 20:49:58 +00008import urllib.request
Ronald Oussorene72e1612011-03-14 18:15:25 -04009# The proxy bypass method imported below has logic specific to the OSX
10# proxy config data structure but is testable on all platforms.
11from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
guido@google.coma119df92011-03-29 11:41:02 -070012import urllib.error
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 Kumaran673d7e92010-01-10 17:48:37 +000027
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000028 # And more hacking to get it to work on MacOS. This assumes
29 # urllib.pathname2url works, unfortunately...
30 if os.name == 'mac':
31 fname = '/' + fname.replace(':', '/')
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000032
Senthil Kumaran673d7e92010-01-10 17:48:37 +000033 if os.name == 'nt':
34 file_url = "file:///%s" % fname
35 else:
36 file_url = "file://%s" % fname
37
Jeremy Hylton1afc1692008-06-18 20:49:58 +000038 f = urllib.request.urlopen(file_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000039
40 buf = f.read()
41 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000042
Georg Brandle1b13d22005-08-24 22:20:32 +000043 def test_parse_http_list(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000044 tests = [
45 ('a,b,c', ['a', 'b', 'c']),
46 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
47 ('a, b, "c", "d", "e,f", g, h',
48 ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
49 ('a="b\\"c", d="e\\,f", g="h\\\\i"',
50 ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
Georg Brandle1b13d22005-08-24 22:20:32 +000051 for string, list in tests:
Florent Xiclunab4efb3d2010-08-14 18:24:40 +000052 self.assertEqual(urllib.request.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000053
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000054
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000055def test_request_headers_dict():
56 """
57 The Request.headers dictionary is not a documented interface. It should
58 stay that way, because the complete set of headers are only accessible
59 through the .get_header(), .has_header(), .header_items() interface.
60 However, .headers pre-dates those methods, and so real code will be using
61 the dictionary.
62
63 The introduction in 2.4 of those methods was a mistake for the same reason:
64 code that previously saw all (urllib2 user)-provided headers in .headers
65 now sees only a subset (and the function interface is ugly and incomplete).
66 A better change would have been to replace .headers dict with a dict
67 subclass (or UserDict.DictMixin instance?) that preserved the .headers
68 interface and also provided access to the "unredirected" headers. It's
69 probably too late to fix that, though.
70
71
72 Check .capitalize() case normalization:
73
74 >>> url = "http://example.com"
75 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
76 'blah'
77 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
78 'blah'
79
80 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
81 but that could be changed in future.
82
83 """
84
85def test_request_headers_methods():
86 """
87 Note the case normalization of header names here, to .capitalize()-case.
88 This should be preserved for backwards-compatibility. (In the HTTP case,
89 normalization to .title()-case is done by urllib2 before sending headers to
Georg Brandl24420152008-05-26 16:32:26 +000090 http.client).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000091
92 >>> url = "http://example.com"
93 >>> r = Request(url, headers={"Spam-eggs": "blah"})
94 >>> r.has_header("Spam-eggs")
95 True
96 >>> r.header_items()
97 [('Spam-eggs', 'blah')]
98 >>> r.add_header("Foo-Bar", "baz")
Guido van Rossumcc2b0162007-02-11 06:12:03 +000099 >>> items = sorted(r.header_items())
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000100 >>> items
101 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
102
103 Note that e.g. r.has_header("spam-EggS") is currently False, and
104 r.get_header("spam-EggS") returns None, but that could be changed in
105 future.
106
107 >>> r.has_header("Not-there")
108 False
Guido van Rossum7131f842007-02-09 20:13:25 +0000109 >>> print(r.get_header("Not-there"))
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000110 None
111 >>> r.get_header("Not-there", "default")
112 'default'
113
114 """
115
116
Thomas Wouters477c8d52006-05-27 19:21:47 +0000117def test_password_manager(self):
118 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000119 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000120 >>> add = mgr.add_password
121 >>> add("Some Realm", "http://example.com/", "joe", "password")
122 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
123 >>> add("c", "http://example.com/foo", "foo", "ni")
124 >>> add("c", "http://example.com/bar", "bar", "nini")
125 >>> add("b", "http://example.com/", "first", "blah")
126 >>> add("b", "http://example.com/", "second", "spam")
127 >>> add("a", "http://example.com", "1", "a")
128 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
129 >>> add("Some Realm", "d.example.com", "4", "d")
130 >>> add("Some Realm", "e.example.com:3128", "5", "e")
131
132 >>> mgr.find_user_password("Some Realm", "example.com")
133 ('joe', 'password')
134 >>> mgr.find_user_password("Some Realm", "http://example.com")
135 ('joe', 'password')
136 >>> mgr.find_user_password("Some Realm", "http://example.com/")
137 ('joe', 'password')
138 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
139 ('joe', 'password')
140 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
141 ('joe', 'password')
142 >>> mgr.find_user_password("c", "http://example.com/foo")
143 ('foo', 'ni')
144 >>> mgr.find_user_password("c", "http://example.com/bar")
145 ('bar', 'nini')
146
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000147 Actually, this is really undefined ATM
148## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000149
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000150## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
151## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000152
153 Use latest add_password() in case of conflict:
154
155 >>> mgr.find_user_password("b", "http://example.com/")
156 ('second', 'spam')
157
158 No special relationship between a.example.com and example.com:
159
160 >>> mgr.find_user_password("a", "http://example.com/")
161 ('1', 'a')
162 >>> mgr.find_user_password("a", "http://a.example.com/")
163 (None, None)
164
165 Ports:
166
167 >>> mgr.find_user_password("Some Realm", "c.example.com")
168 (None, None)
169 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
170 ('3', 'c')
171 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
172 ('3', 'c')
173 >>> mgr.find_user_password("Some Realm", "d.example.com")
174 ('4', 'd')
175 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
176 ('5', 'e')
177
178 """
179 pass
180
181
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000182def test_password_manager_default_port(self):
183 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000184 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000185 >>> add = mgr.add_password
186
187 The point to note here is that we can't guess the default port if there's
188 no scheme. This applies to both add_password and find_user_password.
189
190 >>> add("f", "http://g.example.com:80", "10", "j")
191 >>> add("g", "http://h.example.com", "11", "k")
192 >>> add("h", "i.example.com:80", "12", "l")
193 >>> add("i", "j.example.com", "13", "m")
194 >>> mgr.find_user_password("f", "g.example.com:100")
195 (None, None)
196 >>> mgr.find_user_password("f", "g.example.com:80")
197 ('10', 'j')
198 >>> mgr.find_user_password("f", "g.example.com")
199 (None, None)
200 >>> mgr.find_user_password("f", "http://g.example.com:100")
201 (None, None)
202 >>> mgr.find_user_password("f", "http://g.example.com:80")
203 ('10', 'j')
204 >>> mgr.find_user_password("f", "http://g.example.com")
205 ('10', 'j')
206 >>> mgr.find_user_password("g", "h.example.com")
207 ('11', 'k')
208 >>> mgr.find_user_password("g", "h.example.com:80")
209 ('11', 'k')
210 >>> mgr.find_user_password("g", "http://h.example.com:80")
211 ('11', 'k')
212 >>> mgr.find_user_password("h", "i.example.com")
213 (None, None)
214 >>> mgr.find_user_password("h", "i.example.com:80")
215 ('12', 'l')
216 >>> mgr.find_user_password("h", "http://i.example.com:80")
217 ('12', 'l')
218 >>> mgr.find_user_password("i", "j.example.com")
219 ('13', 'm')
220 >>> mgr.find_user_password("i", "j.example.com:80")
221 (None, None)
222 >>> mgr.find_user_password("i", "http://j.example.com")
223 ('13', 'm')
224 >>> mgr.find_user_password("i", "http://j.example.com:80")
225 (None, None)
226
227 """
228
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000229class MockOpener:
230 addheaders = []
Senthil Kumarane9da06f2009-07-19 04:20:12 +0000231 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
232 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000233 def error(self, proto, *args):
234 self.proto, self.args = proto, args
235
236class MockFile:
237 def read(self, count=None): pass
238 def readline(self, count=None): pass
239 def close(self): pass
240
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000241class MockHeaders(dict):
242 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000243 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000244
Guido van Rossum34d19282007-08-09 01:03:29 +0000245class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000246 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000247 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000248 self.code, self.msg, self.headers, self.url = code, msg, headers, url
249 def info(self):
250 return self.headers
251 def geturl(self):
252 return self.url
253
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000254class MockCookieJar:
255 def add_cookie_header(self, request):
256 self.ach_req = request
257 def extract_cookies(self, response, request):
258 self.ec_req, self.ec_r = request, response
259
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000260class FakeMethod:
261 def __init__(self, meth_name, action, handle):
262 self.meth_name = meth_name
263 self.handle = handle
264 self.action = action
265 def __call__(self, *args):
266 return self.handle(self.meth_name, self.action, *args)
267
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +0000268class MockHTTPResponse(io.IOBase):
269 def __init__(self, fp, msg, status, reason):
270 self.fp = fp
271 self.msg = msg
272 self.status = status
273 self.reason = reason
274 self.code = 200
275
276 def read(self):
277 return ''
278
279 def info(self):
280 return {}
281
282 def geturl(self):
283 return self.url
284
285
286class MockHTTPClass:
287 def __init__(self):
288 self.level = 0
289 self.req_headers = []
290 self.data = None
291 self.raise_on_endheaders = False
292 self._tunnel_headers = {}
293
294 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
295 self.host = host
296 self.timeout = timeout
297 return self
298
299 def set_debuglevel(self, level):
300 self.level = level
301
302 def _set_tunnel(self, host, port=None, headers=None):
303 self._tunnel_host = host
304 self._tunnel_port = port
305 if headers:
306 self._tunnel_headers = headers
307 else:
308 self._tunnel_headers.clear()
309
Benjamin Peterson794921a2009-12-24 01:18:13 +0000310 def request(self, method, url, body=None, headers=None):
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +0000311 self.method = method
312 self.selector = url
Benjamin Peterson794921a2009-12-24 01:18:13 +0000313 if headers is not None:
314 self.req_headers += headers.items()
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +0000315 self.req_headers.sort()
316 if body:
317 self.data = body
318 if self.raise_on_endheaders:
319 import socket
320 raise socket.error()
321 def getresponse(self):
322 return MockHTTPResponse(MockFile(), {}, 200, "OK")
323
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000324class MockHandler:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000325 # useful for testing handler machinery
326 # see add_ordered_mock_handlers() docstring
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000327 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000328 def __init__(self, methods):
329 self._define_methods(methods)
330 def _define_methods(self, methods):
331 for spec in methods:
332 if len(spec) == 2: name, action = spec
333 else: name, action = spec, None
334 meth = FakeMethod(name, action, self.handle)
335 setattr(self.__class__, name, meth)
336 def handle(self, fn_name, action, *args, **kwds):
337 self.parent.calls.append((self, fn_name, args, kwds))
338 if action is None:
339 return None
340 elif action == "return self":
341 return self
342 elif action == "return response":
343 res = MockResponse(200, "OK", {}, "")
344 return res
345 elif action == "return request":
346 return Request("http://blah/")
347 elif action.startswith("error"):
348 code = action[action.rfind(" ")+1:]
349 try:
350 code = int(code)
351 except ValueError:
352 pass
353 res = MockResponse(200, "OK", {}, "")
354 return self.parent.error("http", args[0], res, code, "", {})
355 elif action == "raise":
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000356 raise urllib.error.URLError("blah")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000357 assert False
358 def close(self): pass
359 def add_parent(self, parent):
360 self.parent = parent
361 self.parent.calls = []
362 def __lt__(self, other):
363 if not hasattr(other, "handler_order"):
364 # No handler_order, leave in original order. Yuck.
365 return True
366 return self.handler_order < other.handler_order
367
368def add_ordered_mock_handlers(opener, meth_spec):
369 """Create MockHandlers and add them to an OpenerDirector.
370
371 meth_spec: list of lists of tuples and strings defining methods to define
372 on handlers. eg:
373
374 [["http_error", "ftp_open"], ["http_open"]]
375
376 defines methods .http_error() and .ftp_open() on one handler, and
377 .http_open() on another. These methods just record their arguments and
378 return None. Using a tuple instead of a string causes the method to
379 perform some action (see MockHandler.handle()), eg:
380
381 [["http_error"], [("http_open", "return request")]]
382
383 defines .http_error() on one handler (which simply returns None), and
384 .http_open() on another handler, which returns a Request object.
385
386 """
387 handlers = []
388 count = 0
389 for meths in meth_spec:
390 class MockHandlerSubclass(MockHandler): pass
391 h = MockHandlerSubclass(meths)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000392 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000393 h.add_parent(opener)
394 count = count + 1
395 handlers.append(h)
396 opener.add_handler(h)
397 return handlers
398
Thomas Wouters477c8d52006-05-27 19:21:47 +0000399def build_test_opener(*handler_instances):
400 opener = OpenerDirector()
401 for h in handler_instances:
402 opener.add_handler(h)
403 return opener
404
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000405class MockHTTPHandler(urllib.request.BaseHandler):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000406 # useful for testing redirections and auth
407 # sends supplied headers and code as first response
408 # sends 200 OK as second response
409 def __init__(self, code, headers):
410 self.code = code
411 self.headers = headers
412 self.reset()
413 def reset(self):
414 self._count = 0
415 self.requests = []
416 def http_open(self, req):
Barry Warsaw820c1202008-06-12 04:06:45 +0000417 import email, http.client, copy
Guido van Rossum34d19282007-08-09 01:03:29 +0000418 from io import StringIO
Thomas Wouters477c8d52006-05-27 19:21:47 +0000419 self.requests.append(copy.deepcopy(req))
420 if self._count == 0:
421 self._count = self._count + 1
Georg Brandl24420152008-05-26 16:32:26 +0000422 name = http.client.responses[self.code]
Barry Warsaw820c1202008-06-12 04:06:45 +0000423 msg = email.message_from_string(self.headers)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000424 return self.parent.error(
425 "http", req, MockFile(), self.code, name, msg)
426 else:
427 self.req = req
Barry Warsaw820c1202008-06-12 04:06:45 +0000428 msg = email.message_from_string("\r\n\r\n")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000429 return MockResponse(200, "OK", msg, "", req.get_full_url())
430
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +0000431class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
432 # Useful for testing the Proxy-Authorization request by verifying the
433 # properties of httpcon
Benjamin Peterson794921a2009-12-24 01:18:13 +0000434
435 def __init__(self):
436 urllib.request.AbstractHTTPHandler.__init__(self)
437 self.httpconn = MockHTTPClass()
438
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +0000439 def https_open(self, req):
440 return self.do_open(self.httpconn, req)
441
Thomas Wouters477c8d52006-05-27 19:21:47 +0000442class MockPasswordManager:
443 def add_password(self, realm, uri, user, password):
444 self.realm = realm
445 self.url = uri
446 self.user = user
447 self.password = password
448 def find_user_password(self, realm, authuri):
449 self.target_realm = realm
450 self.target_url = authuri
451 return self.user, self.password
452
453
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000454class OpenerDirectorTests(unittest.TestCase):
455
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000456 def test_add_non_handler(self):
457 class NonHandler(object):
458 pass
459 self.assertRaises(TypeError,
460 OpenerDirector().add_handler, NonHandler())
461
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000462 def test_badly_named_methods(self):
463 # test work-around for three methods that accidentally follow the
464 # naming conventions for handler methods
465 # (*_open() / *_request() / *_response())
466
467 # These used to call the accidentally-named methods, causing a
468 # TypeError in real code; here, returning self from these mock
469 # methods would either cause no exception, or AttributeError.
470
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000471 from urllib.error import URLError
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000472
473 o = OpenerDirector()
474 meth_spec = [
475 [("do_open", "return self"), ("proxy_open", "return self")],
476 [("redirect_request", "return self")],
477 ]
478 handlers = add_ordered_mock_handlers(o, meth_spec)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000479 o.add_handler(urllib.request.UnknownHandler())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000480 for scheme in "do", "proxy", "redirect":
481 self.assertRaises(URLError, o.open, scheme+"://example.com/")
482
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000483 def test_handled(self):
484 # handler returning non-None means no more handlers will be called
485 o = OpenerDirector()
486 meth_spec = [
487 ["http_open", "ftp_open", "http_error_302"],
488 ["ftp_open"],
489 [("http_open", "return self")],
490 [("http_open", "return self")],
491 ]
492 handlers = add_ordered_mock_handlers(o, meth_spec)
493
494 req = Request("http://example.com/")
495 r = o.open(req)
496 # Second .http_open() gets called, third doesn't, since second returned
497 # non-None. Handlers without .http_open() never get any methods called
498 # on them.
499 # In fact, second mock handler defining .http_open() returns self
500 # (instead of response), which becomes the OpenerDirector's return
501 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000502 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000503 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
504 for expected, got in zip(calls, o.calls):
505 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000506 self.assertEqual((handler, name), expected)
507 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000508
509 def test_handler_order(self):
510 o = OpenerDirector()
511 handlers = []
512 for meths, handler_order in [
513 ([("http_open", "return self")], 500),
514 (["http_open"], 0),
515 ]:
516 class MockHandlerSubclass(MockHandler): pass
517 h = MockHandlerSubclass(meths)
518 h.handler_order = handler_order
519 handlers.append(h)
520 o.add_handler(h)
521
522 r = o.open("http://example.com/")
523 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000524 self.assertEqual(o.calls[0][0], handlers[1])
525 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000526
527 def test_raise(self):
528 # raising URLError stops processing of request
529 o = OpenerDirector()
530 meth_spec = [
531 [("http_open", "raise")],
532 [("http_open", "return self")],
533 ]
534 handlers = add_ordered_mock_handlers(o, meth_spec)
535
536 req = Request("http://example.com/")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000537 self.assertRaises(urllib.error.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000538 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000539
540## def test_error(self):
541## # XXX this doesn't actually seem to be used in standard library,
542## # but should really be tested anyway...
543
544 def test_http_error(self):
545 # XXX http_error_default
546 # http errors are a special case
547 o = OpenerDirector()
548 meth_spec = [
549 [("http_open", "error 302")],
550 [("http_error_400", "raise"), "http_open"],
551 [("http_error_302", "return response"), "http_error_303",
552 "http_error"],
553 [("http_error_302")],
554 ]
555 handlers = add_ordered_mock_handlers(o, meth_spec)
556
557 class Unknown:
558 def __eq__(self, other): return True
559
560 req = Request("http://example.com/")
561 r = o.open(req)
562 assert len(o.calls) == 2
563 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000564 (handlers[2], "http_error_302",
565 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000566 for expected, got in zip(calls, o.calls):
567 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000568 self.assertEqual((handler, method_name), got[:2])
569 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000570
571 def test_processors(self):
572 # *_request / *_response methods get called appropriately
573 o = OpenerDirector()
574 meth_spec = [
575 [("http_request", "return request"),
576 ("http_response", "return response")],
577 [("http_request", "return request"),
578 ("http_response", "return response")],
579 ]
580 handlers = add_ordered_mock_handlers(o, meth_spec)
581
582 req = Request("http://example.com/")
583 r = o.open(req)
584 # processor methods are called on *all* handlers that define them,
585 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000586 calls = [
587 (handlers[0], "http_request"), (handlers[1], "http_request"),
588 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000589
590 for i, (handler, name, args, kwds) in enumerate(o.calls):
591 if i < 2:
592 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000593 self.assertEqual((handler, name), calls[i])
594 self.assertEqual(len(args), 1)
Georg Brandlab91fde2009-08-13 08:51:18 +0000595 self.assertTrue(isinstance(args[0], Request))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000596 else:
597 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000598 self.assertEqual((handler, name), calls[i])
599 self.assertEqual(len(args), 2)
Georg Brandlab91fde2009-08-13 08:51:18 +0000600 self.assertTrue(isinstance(args[0], Request))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000601 # response from opener.open is None, because there's no
602 # handler that defines http_open to handle it
Georg Brandlab91fde2009-08-13 08:51:18 +0000603 self.assertTrue(args[1] is None or
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000604 isinstance(args[1], MockResponse))
605
606
Tim Peters58eb11c2004-01-18 20:29:55 +0000607def sanepathname2url(path):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000608 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000609 if os.name == "nt" and urlpath.startswith("///"):
610 urlpath = urlpath[2:]
611 # XXX don't ask me about the mac...
612 return urlpath
613
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000614class HandlerTests(unittest.TestCase):
615
616 def test_ftp(self):
617 class MockFTPWrapper:
618 def __init__(self, data): self.data = data
619 def retrfile(self, filename, filetype):
620 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000621 return io.StringIO(self.data), len(self.data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000622
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000623 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000624 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000625 def connect_ftp(self, user, passwd, host, port, dirs,
626 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000627 self.user, self.passwd = user, passwd
628 self.host, self.port = host, port
629 self.dirs = dirs
630 self.ftpwrapper = MockFTPWrapper(self.data)
631 return self.ftpwrapper
632
Georg Brandlf78e02b2008-06-10 17:40:04 +0000633 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000634 data = "rheum rhaponicum"
635 h = NullFTPHandler(data)
636 o = h.parent = MockOpener()
637
Senthil Kumaran723a7a62010-11-18 16:44:38 +0000638 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000639 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumaran723a7a62010-11-18 16:44:38 +0000640 "localhost", ftplib.FTP_PORT, "", "", "I",
641 ["foo", "bar"], "baz.html", "text/html"),
642 ("ftp://parrot@localhost/foo/bar/baz.html",
643 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
644 ["foo", "bar"], "baz.html", "text/html"),
645 ("ftp://%25parrot@localhost/foo/bar/baz.html",
646 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
647 ["foo", "bar"], "baz.html", "text/html"),
648 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
649 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000650 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000651 ("ftp://localhost:80/foo/bar/",
Senthil Kumaran723a7a62010-11-18 16:44:38 +0000652 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000653 ["foo", "bar"], "", None),
654 ("ftp://localhost/baz.gif;type=a",
Senthil Kumaran723a7a62010-11-18 16:44:38 +0000655 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000656 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000657 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000658 req = Request(url)
659 req.timeout = None
660 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000661 # ftp authentication not yet implemented by FTPHandler
Senthil Kumaran723a7a62010-11-18 16:44:38 +0000662 self.assertEqual(h.user, user)
663 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000664 self.assertEqual(h.host, socket.gethostbyname(host))
665 self.assertEqual(h.port, port)
666 self.assertEqual(h.dirs, dirs)
667 self.assertEqual(h.ftpwrapper.filename, filename)
668 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000669 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000670 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000671 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000672
673 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000674 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000675 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000676 o = h.parent = MockOpener()
677
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000678 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000679 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000680 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000681 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000682 "file://localhost%s" % urlpath,
683 "file://%s" % urlpath,
684 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000685 ]
686 try:
687 localaddr = socket.gethostbyname(socket.gethostname())
688 except socket.gaierror:
689 localaddr = ''
690 if localaddr:
691 urls.append("file://%s%s" % (localaddr, urlpath))
692
693 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000694 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000695 try:
696 try:
697 f.write(towrite)
698 finally:
699 f.close()
700
701 r = h.file_open(Request(url))
702 try:
703 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000704 headers = r.info()
Senthil Kumaran51964772010-05-08 03:31:56 +0000705 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000706 finally:
707 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000708 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000709 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000710 finally:
711 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000712 self.assertEqual(data, towrite)
713 self.assertEqual(headers["Content-type"], "text/plain")
714 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000715 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran51964772010-05-08 03:31:56 +0000716 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000717
718 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000719 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000720 "file:///file_does_not_exist.txt",
721 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
722 os.getcwd(), TESTFN),
723 "file://somerandomhost.ontheinternet.com%s/%s" %
724 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000725 ]:
726 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000727 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000728 try:
729 f.write(towrite)
730 finally:
731 f.close()
732
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000733 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000734 h.file_open, Request(url))
735 finally:
736 os.remove(TESTFN)
737
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000738 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000739 o = h.parent = MockOpener()
740 # XXXX why does // mean ftp (and /// mean not ftp!), and where
741 # is file: scheme specified? I think this is really a bug, and
742 # what was intended was to distinguish between URLs like:
743 # file:/blah.txt (a file)
744 # file://localhost/blah.txt (a file)
745 # file:///blah.txt (a file)
746 # file://ftp.example.com/blah.txt (an ftp URL)
747 for url, ftp in [
748 ("file://ftp.example.com//foo.txt", True),
749 ("file://ftp.example.com///foo.txt", False),
750# XXXX bug: fails with OSError, should be URLError
751 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran34024142010-07-11 03:15:25 +0000752 ("file://somehost//foo/something.txt", True),
753 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000754 ]:
755 req = Request(url)
756 try:
757 h.file_open(req)
758 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000759 except (urllib.error.URLError, OSError):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000760 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000761 else:
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000762 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000763 self.assertEqual(req.type, "ftp")
Benjamin Petersonecb6e812011-01-12 19:29:51 +0000764 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000765
766 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000767
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000768 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000769 o = h.parent = MockOpener()
770
771 url = "http://example.com/"
772 for method, data in [("GET", None), ("POST", "blah")]:
773 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000774 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000775 req.add_unredirected_header("Spam", "eggs")
776 http = MockHTTPClass()
777 r = h.do_open(http, req)
778
779 # result attributes
780 r.read; r.readline # wrapped MockFile methods
781 r.info; r.geturl # addinfourl methods
782 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
783 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000784 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000785 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000786
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000787 self.assertEqual(http.host, "example.com")
788 self.assertEqual(http.level, 0)
789 self.assertEqual(http.method, method)
790 self.assertEqual(http.selector, "/")
791 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000792 [("Connection", "close"),
793 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000794 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000795
796 # check socket.error converted to URLError
797 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000798 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000799
800 # check adding of standard headers
801 o.addheaders = [("Spam", "eggs")]
802 for data in "", None: # POST, GET
803 req = Request("http://example.com/", data)
804 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000805 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000806 if data is None: # GET
Georg Brandlab91fde2009-08-13 08:51:18 +0000807 self.assertTrue("Content-length" not in req.unredirected_hdrs)
808 self.assertTrue("Content-type" not in req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000809 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000810 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
811 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000812 "application/x-www-form-urlencoded")
813 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000814 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
815 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000816
817 # don't clobber existing headers
818 req.add_unredirected_header("Content-length", "foo")
819 req.add_unredirected_header("Content-type", "bar")
820 req.add_unredirected_header("Host", "baz")
821 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000822 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000823 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
824 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000825 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
826 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000827
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000828 def test_http_doubleslash(self):
829 # Checks the presence of any unnecessary double slash in url does not
830 # break anything. Previously, a double slash directly after the host
831 # could could cause incorrect parsing.
832 h = urllib.request.AbstractHTTPHandler()
833 o = h.parent = MockOpener()
834
835 data = ""
836 ds_urls = [
837 "http://example.com/foo/bar/baz.html",
838 "http://example.com//foo/bar/baz.html",
839 "http://example.com/foo//bar/baz.html",
840 "http://example.com/foo/bar//baz.html"
841 ]
842
843 for ds_url in ds_urls:
844 ds_req = Request(ds_url, data)
845
846 # Check whether host is determined correctly if there is no proxy
847 np_ds_req = h.do_request_(ds_req)
848 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
849
850 # Check whether host is determined correctly if there is a proxy
851 ds_req.set_proxy("someproxy:3128",None)
852 p_ds_req = h.do_request_(ds_req)
853 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
854
Senthil Kumarand17ebdb2010-11-22 04:53:57 +0000855 def test_fixpath_in_weirdurls(self):
856 # Issue4493: urllib2 to supply '/' when to urls where path does not
857 # start with'/'
858
859 h = urllib.request.AbstractHTTPHandler()
860 o = h.parent = MockOpener()
861
862 weird_url = 'http://www.python.org?getspam'
863 req = Request(weird_url)
864 newreq = h.do_request_(req)
865 self.assertEqual(newreq.host,'www.python.org')
866 self.assertEqual(newreq.selector,'/?getspam')
867
868 url_without_path = 'http://www.python.org'
869 req = Request(url_without_path)
870 newreq = h.do_request_(req)
871 self.assertEqual(newreq.host,'www.python.org')
872 self.assertEqual(newreq.selector,'')
873
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000874
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000875 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000876 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000877 o = h.parent = MockOpener()
878
879 url = "http://example.com/"
880 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000881 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000882 r = MockResponse(200, "OK", {}, "", url)
883 newr = h.http_response(req, r)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000884 self.assertIs(r, newr)
885 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000886 r = MockResponse(202, "Accepted", {}, "", url)
887 newr = h.http_response(req, r)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000888 self.assertIs(r, newr)
889 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000890 r = MockResponse(206, "Partial content", {}, "", url)
891 newr = h.http_response(req, r)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000892 self.assertIs(r, newr)
893 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000894 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000895 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000896 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000897 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000898 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000899
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000900 def test_cookies(self):
901 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000902 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000903 o = h.parent = MockOpener()
904
905 req = Request("http://example.com/")
906 r = MockResponse(200, "OK", {}, "")
907 newreq = h.http_request(req)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000908 self.assertIs(cj.ach_req, req)
909 self.assertIs(cj.ach_req, newreq)
910 self.assertEqual(req.get_origin_req_host(), "example.com")
911 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000912 newr = h.http_response(req, r)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000913 self.assertIs(cj.ec_req, req)
914 self.assertIs(cj.ec_r, r)
915 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000916
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000917 def test_redirect(self):
918 from_url = "http://example.com/a.html"
919 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000920 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000921 o = h.parent = MockOpener()
922
923 # ordinary redirect behaviour
924 for code in 301, 302, 303, 307:
925 for data in None, "blah\nblah\n":
926 method = getattr(h, "http_error_%s" % code)
927 req = Request(from_url, data)
Senthil Kumarane9da06f2009-07-19 04:20:12 +0000928 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000929 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000930 if data is not None:
931 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000932 req.add_unredirected_header("Spam", "spam")
933 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000934 method(req, MockFile(), code, "Blah",
935 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000936 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000937 # 307 in response to POST requires user OK
Georg Brandlab91fde2009-08-13 08:51:18 +0000938 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000939 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000940 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000941 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000942 except AttributeError:
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000943 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +0000944
945 # now it's a GET, there should not be headers regarding content
946 # (possibly dragged from before being a POST)
947 headers = [x.lower() for x in o.req.headers]
948 self.assertTrue("content-length" not in headers)
949 self.assertTrue("content-type" not in headers)
950
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000951 self.assertEqual(o.req.headers["Nonsense"],
952 "viking=withhold")
Georg Brandlab91fde2009-08-13 08:51:18 +0000953 self.assertTrue("Spam" not in o.req.headers)
954 self.assertTrue("Spam" not in o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000955
956 # loop detection
957 req = Request(from_url)
Senthil Kumarane9da06f2009-07-19 04:20:12 +0000958 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000959 def redirect(h, req, url=to_url):
960 h.http_error_302(req, MockFile(), 302, "Blah",
961 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000962 # Note that the *original* request shares the same record of
963 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000964
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000965 # detect infinite loop redirect of a URL to itself
966 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000967 count = 0
Senthil Kumarane9da06f2009-07-19 04:20:12 +0000968 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000969 try:
970 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000971 redirect(h, req, "http://example.com/")
972 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000973 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000974 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000975 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000976
977 # detect endless non-repeating chain of redirects
978 req = Request(from_url, origin_req_host="example.com")
979 count = 0
Senthil Kumarane9da06f2009-07-19 04:20:12 +0000980 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000981 try:
982 while 1:
983 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000984 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000985 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000986 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000987 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000988
guido@google.coma119df92011-03-29 11:41:02 -0700989
990 def test_invalid_redirect(self):
991 from_url = "http://example.com/a.html"
992 valid_schemes = ['http','https','ftp']
993 invalid_schemes = ['file','imap','ldap']
994 schemeless_url = "example.com/b.html"
995 h = urllib.request.HTTPRedirectHandler()
996 o = h.parent = MockOpener()
997 req = Request(from_url)
998 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
999
1000 for scheme in invalid_schemes:
1001 invalid_url = scheme + '://' + schemeless_url
1002 self.assertRaises(urllib.error.HTTPError, h.http_error_302,
1003 req, MockFile(), 302, "Security Loophole",
1004 MockHeaders({"location": invalid_url}))
1005
1006 for scheme in valid_schemes:
1007 valid_url = scheme + '://' + schemeless_url
1008 h.http_error_302(req, MockFile(), 302, "That's fine",
1009 MockHeaders({"location": valid_url}))
1010 self.assertEqual(o.req.get_full_url(), valid_url)
1011
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001012 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001013 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001014 from http.cookiejar import CookieJar
1015 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001016
1017 cj = CookieJar()
1018 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001019 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001020 hdeh = urllib.request.HTTPDefaultErrorHandler()
1021 hrh = urllib.request.HTTPRedirectHandler()
1022 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001023 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001024 o.open("http://www.example.com/")
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001025 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001026
Senthil Kumaran26430412011-04-13 07:01:19 +08001027 def test_redirect_fragment(self):
1028 redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
1029 hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
1030 hdeh = urllib.request.HTTPDefaultErrorHandler()
1031 hrh = urllib.request.HTTPRedirectHandler()
1032 o = build_test_opener(hh, hdeh, hrh)
1033 fp = o.open('http://www.example.com')
1034 self.assertEqual(fp.geturl(), redirected_url.strip())
1035
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001036 def test_proxy(self):
1037 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001038 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001039 o.add_handler(ph)
1040 meth_spec = [
1041 [("http_open", "return response")]
1042 ]
1043 handlers = add_ordered_mock_handlers(o, meth_spec)
1044
1045 req = Request("http://acme.example.com/")
1046 self.assertEqual(req.get_host(), "acme.example.com")
1047 r = o.open(req)
1048 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1049
1050 self.assertEqual([(handlers[0], "http_open")],
1051 [tup[0:2] for tup in o.calls])
1052
Senthil Kumaran11301632009-10-11 06:07:46 +00001053 def test_proxy_no_proxy(self):
1054 os.environ['no_proxy'] = 'python.org'
1055 o = OpenerDirector()
1056 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1057 o.add_handler(ph)
1058 req = Request("http://www.perl.org/")
1059 self.assertEqual(req.get_host(), "www.perl.org")
1060 r = o.open(req)
1061 self.assertEqual(req.get_host(), "proxy.example.com")
1062 req = Request("http://www.python.org")
1063 self.assertEqual(req.get_host(), "www.python.org")
1064 r = o.open(req)
1065 self.assertEqual(req.get_host(), "www.python.org")
1066 del os.environ['no_proxy']
1067
Ronald Oussorene72e1612011-03-14 18:15:25 -04001068 def test_proxy_no_proxy_all(self):
1069 os.environ['no_proxy'] = '*'
1070 o = OpenerDirector()
1071 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1072 o.add_handler(ph)
1073 req = Request("http://www.python.org")
1074 self.assertEqual(req.get_host(), "www.python.org")
1075 r = o.open(req)
1076 self.assertEqual(req.get_host(), "www.python.org")
1077 del os.environ['no_proxy']
1078
Senthil Kumaran11301632009-10-11 06:07:46 +00001079
Senthil Kumaran0ac1f832009-07-26 12:39:47 +00001080 def test_proxy_https(self):
1081 o = OpenerDirector()
1082 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1083 o.add_handler(ph)
1084 meth_spec = [
1085 [("https_open", "return response")]
1086 ]
1087 handlers = add_ordered_mock_handlers(o, meth_spec)
1088
1089 req = Request("https://www.example.com/")
1090 self.assertEqual(req.get_host(), "www.example.com")
1091 r = o.open(req)
1092 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1093 self.assertEqual([(handlers[0], "https_open")],
1094 [tup[0:2] for tup in o.calls])
1095
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +00001096 def test_proxy_https_proxy_authorization(self):
1097 o = OpenerDirector()
1098 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1099 o.add_handler(ph)
1100 https_handler = MockHTTPSHandler()
1101 o.add_handler(https_handler)
1102 req = Request("https://www.example.com/")
1103 req.add_header("Proxy-Authorization","FooBar")
1104 req.add_header("User-Agent","Grail")
1105 self.assertEqual(req.get_host(), "www.example.com")
1106 self.assertIsNone(req._tunnel_host)
1107 r = o.open(req)
1108 # Verify Proxy-Authorization gets tunneled to request.
1109 # httpsconn req_headers do not have the Proxy-Authorization header but
1110 # the req will have.
1111 self.assertFalse(("Proxy-Authorization","FooBar") in
1112 https_handler.httpconn.req_headers)
1113 self.assertTrue(("User-Agent","Grail") in
1114 https_handler.httpconn.req_headers)
1115 self.assertIsNotNone(req._tunnel_host)
1116 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1117 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran0ac1f832009-07-26 12:39:47 +00001118
Ronald Oussorene72e1612011-03-14 18:15:25 -04001119 def test_osx_proxy_bypass(self):
1120 bypass = {
1121 'exclude_simple': False,
1122 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1123 '10.0/16']
1124 }
1125 # Check hosts that should trigger the proxy bypass
1126 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1127 '10.0.0.1'):
1128 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1129 'expected bypass of %s to be True' % host)
1130 # Check hosts that should not trigger the proxy bypass
1131 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1132 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1133 'expected bypass of %s to be False' % host)
1134
1135 # Check the exclude_simple flag
1136 bypass = {'exclude_simple': True, 'exceptions': []}
1137 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1138
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001139 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001140 opener = OpenerDirector()
1141 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001142 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001143 realm = "ACME Widget Store"
1144 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001145 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1146 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001147 opener.add_handler(auth_handler)
1148 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001149 self._test_basic_auth(opener, auth_handler, "Authorization",
1150 realm, http_handler, password_manager,
1151 "http://acme.example.com/protected",
1152 "http://acme.example.com/protected",
1153 )
1154
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001155 def test_basic_auth_with_single_quoted_realm(self):
1156 self.test_basic_auth(quote_char="'")
1157
Thomas Wouters477c8d52006-05-27 19:21:47 +00001158 def test_proxy_basic_auth(self):
1159 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001160 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001161 opener.add_handler(ph)
1162 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001163 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001164 realm = "ACME Networks"
1165 http_handler = MockHTTPHandler(
1166 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001167 opener.add_handler(auth_handler)
1168 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001169 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001170 realm, http_handler, password_manager,
1171 "http://acme.example.com:3128/protected",
1172 "proxy.example.com:3128",
1173 )
1174
1175 def test_basic_and_digest_auth_handlers(self):
1176 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1177 # response (http://python.org/sf/1479302), where it should instead
1178 # return None to allow another handler (especially
1179 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001180
1181 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1182 # try digest first (since it's the strongest auth scheme), so we record
1183 # order of calls here to check digest comes first:
1184 class RecordingOpenerDirector(OpenerDirector):
1185 def __init__(self):
1186 OpenerDirector.__init__(self)
1187 self.recorded = []
1188 def record(self, info):
1189 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001190 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001191 def http_error_401(self, *args, **kwds):
1192 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001193 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001194 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001195 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001196 def http_error_401(self, *args, **kwds):
1197 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001198 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001199 *args, **kwds)
1200
1201 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001202 password_manager = MockPasswordManager()
1203 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001204 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001205 realm = "ACME Networks"
1206 http_handler = MockHTTPHandler(
1207 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001208 opener.add_handler(basic_handler)
1209 opener.add_handler(digest_handler)
1210 opener.add_handler(http_handler)
1211
1212 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001213 self._test_basic_auth(opener, basic_handler, "Authorization",
1214 realm, http_handler, password_manager,
1215 "http://acme.example.com/protected",
1216 "http://acme.example.com/protected",
1217 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001218 # check digest was tried before basic (twice, because
1219 # _test_basic_auth called .open() twice)
1220 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001221
1222 def _test_basic_auth(self, opener, auth_handler, auth_header,
1223 realm, http_handler, password_manager,
1224 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001225 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001226 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001227
1228 # .add_password() fed through to password manager
1229 auth_handler.add_password(realm, request_url, user, password)
1230 self.assertEqual(realm, password_manager.realm)
1231 self.assertEqual(request_url, password_manager.url)
1232 self.assertEqual(user, password_manager.user)
1233 self.assertEqual(password, password_manager.password)
1234
1235 r = opener.open(request_url)
1236
1237 # should have asked the password manager for the username/password
1238 self.assertEqual(password_manager.target_realm, realm)
1239 self.assertEqual(password_manager.target_url, protected_url)
1240
1241 # expect one request without authorization, then one with
1242 self.assertEqual(len(http_handler.requests), 2)
1243 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001244 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001245 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001246 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001247 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1248 auth_hdr_value)
Senthil Kumaranefcd8832010-02-24 16:56:20 +00001249 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1250 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001251 # if the password manager can't find a password, the handler won't
1252 # handle the HTTP auth error
1253 password_manager.user = password_manager.password = None
1254 http_handler.reset()
1255 r = opener.open(request_url)
1256 self.assertEqual(len(http_handler.requests), 1)
1257 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1258
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001259class MiscTests(unittest.TestCase):
1260
1261 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001262 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1263 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001264 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001265 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001266 def bar_open(self): pass
1267
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001268 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001269
1270 o = build_opener(FooHandler, BarHandler)
1271 self.opener_has_handler(o, FooHandler)
1272 self.opener_has_handler(o, BarHandler)
1273
1274 # can take a mix of classes and instances
1275 o = build_opener(FooHandler, BarHandler())
1276 self.opener_has_handler(o, FooHandler)
1277 self.opener_has_handler(o, BarHandler)
1278
1279 # subclasses of default handlers override default handlers
1280 o = build_opener(MyHTTPHandler)
1281 self.opener_has_handler(o, MyHTTPHandler)
1282
1283 # a particular case of overriding: default handlers can be passed
1284 # in explicitly
1285 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001286 self.opener_has_handler(o, urllib.request.HTTPHandler)
1287 o = build_opener(urllib.request.HTTPHandler)
1288 self.opener_has_handler(o, urllib.request.HTTPHandler)
1289 o = build_opener(urllib.request.HTTPHandler())
1290 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001291
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001292 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001293 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001294 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1295 self.opener_has_handler(o, MyHTTPHandler)
1296 self.opener_has_handler(o, MyOtherHTTPHandler)
1297
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001298 def opener_has_handler(self, opener, handler_class):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001299 self.assertTrue(any(h.__class__ == handler_class
1300 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001301
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001302class RequestTests(unittest.TestCase):
1303
1304 def setUp(self):
1305 self.get = Request("http://www.python.org/~jeremy/")
1306 self.post = Request("http://www.python.org/~jeremy/",
1307 "data",
1308 headers={"X-Test": "test"})
1309
1310 def test_method(self):
1311 self.assertEqual("POST", self.post.get_method())
1312 self.assertEqual("GET", self.get.get_method())
1313
1314 def test_add_data(self):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001315 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001316 self.assertEqual("GET", self.get.get_method())
1317 self.get.add_data("spam")
Georg Brandlab91fde2009-08-13 08:51:18 +00001318 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001319 self.assertEqual("POST", self.get.get_method())
1320
1321 def test_get_full_url(self):
1322 self.assertEqual("http://www.python.org/~jeremy/",
1323 self.get.get_full_url())
1324
1325 def test_selector(self):
1326 self.assertEqual("/~jeremy/", self.get.get_selector())
1327 req = Request("http://www.python.org/")
1328 self.assertEqual("/", req.get_selector())
1329
1330 def test_get_type(self):
1331 self.assertEqual("http", self.get.get_type())
1332
1333 def test_get_host(self):
1334 self.assertEqual("www.python.org", self.get.get_host())
1335
1336 def test_get_host_unquote(self):
1337 req = Request("http://www.%70ython.org/")
1338 self.assertEqual("www.python.org", req.get_host())
1339
1340 def test_proxy(self):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001341 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001342 self.get.set_proxy("www.perl.org", "http")
Georg Brandlab91fde2009-08-13 08:51:18 +00001343 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001344 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1345 self.assertEqual("www.perl.org", self.get.get_host())
1346
Senthil Kumaran4c88db72010-08-08 11:30:58 +00001347 def test_wrapped_url(self):
1348 req = Request("<URL:http://www.python.org>")
1349 self.assertEqual("www.python.org", req.get_host())
1350
Senthil Kumaran26430412011-04-13 07:01:19 +08001351 def test_url_fragment(self):
Senthil Kumaran4c88db72010-08-08 11:30:58 +00001352 req = Request("http://www.python.org/?qs=query#fragment=true")
1353 self.assertEqual("/?qs=query", req.get_selector())
1354 req = Request("http://www.python.org/#fun=true")
1355 self.assertEqual("/", req.get_selector())
1356
Senthil Kumaran26430412011-04-13 07:01:19 +08001357 # Issue 11703: geturl() omits fragment in the original URL.
1358 url = 'http://docs.python.org/library/urllib2.html#OK'
1359 req = Request(url)
1360 self.assertEqual(req.get_full_url(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001361
1362def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001363 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001364 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001365 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001366 tests = (TrivialTests,
1367 OpenerDirectorTests,
1368 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001369 MiscTests,
1370 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001371 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001372
1373if __name__ == "__main__":
1374 test_main(verbose=True)