blob: 3fd7baa8ddc072a76561cfe6b556c57488061bef [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
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001027 def test_proxy(self):
1028 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001029 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001030 o.add_handler(ph)
1031 meth_spec = [
1032 [("http_open", "return response")]
1033 ]
1034 handlers = add_ordered_mock_handlers(o, meth_spec)
1035
1036 req = Request("http://acme.example.com/")
1037 self.assertEqual(req.get_host(), "acme.example.com")
1038 r = o.open(req)
1039 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1040
1041 self.assertEqual([(handlers[0], "http_open")],
1042 [tup[0:2] for tup in o.calls])
1043
Senthil Kumaran11301632009-10-11 06:07:46 +00001044 def test_proxy_no_proxy(self):
1045 os.environ['no_proxy'] = 'python.org'
1046 o = OpenerDirector()
1047 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1048 o.add_handler(ph)
1049 req = Request("http://www.perl.org/")
1050 self.assertEqual(req.get_host(), "www.perl.org")
1051 r = o.open(req)
1052 self.assertEqual(req.get_host(), "proxy.example.com")
1053 req = Request("http://www.python.org")
1054 self.assertEqual(req.get_host(), "www.python.org")
1055 r = o.open(req)
1056 self.assertEqual(req.get_host(), "www.python.org")
1057 del os.environ['no_proxy']
1058
Ronald Oussorene72e1612011-03-14 18:15:25 -04001059 def test_proxy_no_proxy_all(self):
1060 os.environ['no_proxy'] = '*'
1061 o = OpenerDirector()
1062 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1063 o.add_handler(ph)
1064 req = Request("http://www.python.org")
1065 self.assertEqual(req.get_host(), "www.python.org")
1066 r = o.open(req)
1067 self.assertEqual(req.get_host(), "www.python.org")
1068 del os.environ['no_proxy']
1069
Senthil Kumaran11301632009-10-11 06:07:46 +00001070
Senthil Kumaran0ac1f832009-07-26 12:39:47 +00001071 def test_proxy_https(self):
1072 o = OpenerDirector()
1073 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1074 o.add_handler(ph)
1075 meth_spec = [
1076 [("https_open", "return response")]
1077 ]
1078 handlers = add_ordered_mock_handlers(o, meth_spec)
1079
1080 req = Request("https://www.example.com/")
1081 self.assertEqual(req.get_host(), "www.example.com")
1082 r = o.open(req)
1083 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1084 self.assertEqual([(handlers[0], "https_open")],
1085 [tup[0:2] for tup in o.calls])
1086
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +00001087 def test_proxy_https_proxy_authorization(self):
1088 o = OpenerDirector()
1089 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1090 o.add_handler(ph)
1091 https_handler = MockHTTPSHandler()
1092 o.add_handler(https_handler)
1093 req = Request("https://www.example.com/")
1094 req.add_header("Proxy-Authorization","FooBar")
1095 req.add_header("User-Agent","Grail")
1096 self.assertEqual(req.get_host(), "www.example.com")
1097 self.assertIsNone(req._tunnel_host)
1098 r = o.open(req)
1099 # Verify Proxy-Authorization gets tunneled to request.
1100 # httpsconn req_headers do not have the Proxy-Authorization header but
1101 # the req will have.
1102 self.assertFalse(("Proxy-Authorization","FooBar") in
1103 https_handler.httpconn.req_headers)
1104 self.assertTrue(("User-Agent","Grail") in
1105 https_handler.httpconn.req_headers)
1106 self.assertIsNotNone(req._tunnel_host)
1107 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1108 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran0ac1f832009-07-26 12:39:47 +00001109
Ronald Oussorene72e1612011-03-14 18:15:25 -04001110 def test_osx_proxy_bypass(self):
1111 bypass = {
1112 'exclude_simple': False,
1113 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1114 '10.0/16']
1115 }
1116 # Check hosts that should trigger the proxy bypass
1117 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1118 '10.0.0.1'):
1119 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1120 'expected bypass of %s to be True' % host)
1121 # Check hosts that should not trigger the proxy bypass
1122 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1123 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1124 'expected bypass of %s to be False' % host)
1125
1126 # Check the exclude_simple flag
1127 bypass = {'exclude_simple': True, 'exceptions': []}
1128 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1129
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001130 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001131 opener = OpenerDirector()
1132 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001133 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001134 realm = "ACME Widget Store"
1135 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001136 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1137 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001138 opener.add_handler(auth_handler)
1139 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001140 self._test_basic_auth(opener, auth_handler, "Authorization",
1141 realm, http_handler, password_manager,
1142 "http://acme.example.com/protected",
1143 "http://acme.example.com/protected",
1144 )
1145
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001146 def test_basic_auth_with_single_quoted_realm(self):
1147 self.test_basic_auth(quote_char="'")
1148
Thomas Wouters477c8d52006-05-27 19:21:47 +00001149 def test_proxy_basic_auth(self):
1150 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001151 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001152 opener.add_handler(ph)
1153 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001154 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001155 realm = "ACME Networks"
1156 http_handler = MockHTTPHandler(
1157 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001158 opener.add_handler(auth_handler)
1159 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001160 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001161 realm, http_handler, password_manager,
1162 "http://acme.example.com:3128/protected",
1163 "proxy.example.com:3128",
1164 )
1165
1166 def test_basic_and_digest_auth_handlers(self):
1167 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1168 # response (http://python.org/sf/1479302), where it should instead
1169 # return None to allow another handler (especially
1170 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001171
1172 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1173 # try digest first (since it's the strongest auth scheme), so we record
1174 # order of calls here to check digest comes first:
1175 class RecordingOpenerDirector(OpenerDirector):
1176 def __init__(self):
1177 OpenerDirector.__init__(self)
1178 self.recorded = []
1179 def record(self, info):
1180 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001181 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001182 def http_error_401(self, *args, **kwds):
1183 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001184 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001185 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001186 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001187 def http_error_401(self, *args, **kwds):
1188 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001189 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001190 *args, **kwds)
1191
1192 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001193 password_manager = MockPasswordManager()
1194 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001195 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001196 realm = "ACME Networks"
1197 http_handler = MockHTTPHandler(
1198 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001199 opener.add_handler(basic_handler)
1200 opener.add_handler(digest_handler)
1201 opener.add_handler(http_handler)
1202
1203 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001204 self._test_basic_auth(opener, basic_handler, "Authorization",
1205 realm, http_handler, password_manager,
1206 "http://acme.example.com/protected",
1207 "http://acme.example.com/protected",
1208 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001209 # check digest was tried before basic (twice, because
1210 # _test_basic_auth called .open() twice)
1211 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001212
1213 def _test_basic_auth(self, opener, auth_handler, auth_header,
1214 realm, http_handler, password_manager,
1215 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001216 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001217 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001218
1219 # .add_password() fed through to password manager
1220 auth_handler.add_password(realm, request_url, user, password)
1221 self.assertEqual(realm, password_manager.realm)
1222 self.assertEqual(request_url, password_manager.url)
1223 self.assertEqual(user, password_manager.user)
1224 self.assertEqual(password, password_manager.password)
1225
1226 r = opener.open(request_url)
1227
1228 # should have asked the password manager for the username/password
1229 self.assertEqual(password_manager.target_realm, realm)
1230 self.assertEqual(password_manager.target_url, protected_url)
1231
1232 # expect one request without authorization, then one with
1233 self.assertEqual(len(http_handler.requests), 2)
1234 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001235 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001236 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001237 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001238 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1239 auth_hdr_value)
Senthil Kumaranefcd8832010-02-24 16:56:20 +00001240 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1241 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001242 # if the password manager can't find a password, the handler won't
1243 # handle the HTTP auth error
1244 password_manager.user = password_manager.password = None
1245 http_handler.reset()
1246 r = opener.open(request_url)
1247 self.assertEqual(len(http_handler.requests), 1)
1248 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1249
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001250class MiscTests(unittest.TestCase):
1251
1252 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001253 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1254 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001255 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001256 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001257 def bar_open(self): pass
1258
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001259 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001260
1261 o = build_opener(FooHandler, BarHandler)
1262 self.opener_has_handler(o, FooHandler)
1263 self.opener_has_handler(o, BarHandler)
1264
1265 # can take a mix of classes and instances
1266 o = build_opener(FooHandler, BarHandler())
1267 self.opener_has_handler(o, FooHandler)
1268 self.opener_has_handler(o, BarHandler)
1269
1270 # subclasses of default handlers override default handlers
1271 o = build_opener(MyHTTPHandler)
1272 self.opener_has_handler(o, MyHTTPHandler)
1273
1274 # a particular case of overriding: default handlers can be passed
1275 # in explicitly
1276 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001277 self.opener_has_handler(o, urllib.request.HTTPHandler)
1278 o = build_opener(urllib.request.HTTPHandler)
1279 self.opener_has_handler(o, urllib.request.HTTPHandler)
1280 o = build_opener(urllib.request.HTTPHandler())
1281 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001282
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001283 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001284 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001285 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1286 self.opener_has_handler(o, MyHTTPHandler)
1287 self.opener_has_handler(o, MyOtherHTTPHandler)
1288
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001289 def opener_has_handler(self, opener, handler_class):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001290 self.assertTrue(any(h.__class__ == handler_class
1291 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001292
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001293class RequestTests(unittest.TestCase):
1294
1295 def setUp(self):
1296 self.get = Request("http://www.python.org/~jeremy/")
1297 self.post = Request("http://www.python.org/~jeremy/",
1298 "data",
1299 headers={"X-Test": "test"})
1300
1301 def test_method(self):
1302 self.assertEqual("POST", self.post.get_method())
1303 self.assertEqual("GET", self.get.get_method())
1304
1305 def test_add_data(self):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001306 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001307 self.assertEqual("GET", self.get.get_method())
1308 self.get.add_data("spam")
Georg Brandlab91fde2009-08-13 08:51:18 +00001309 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001310 self.assertEqual("POST", self.get.get_method())
1311
1312 def test_get_full_url(self):
1313 self.assertEqual("http://www.python.org/~jeremy/",
1314 self.get.get_full_url())
1315
1316 def test_selector(self):
1317 self.assertEqual("/~jeremy/", self.get.get_selector())
1318 req = Request("http://www.python.org/")
1319 self.assertEqual("/", req.get_selector())
1320
1321 def test_get_type(self):
1322 self.assertEqual("http", self.get.get_type())
1323
1324 def test_get_host(self):
1325 self.assertEqual("www.python.org", self.get.get_host())
1326
1327 def test_get_host_unquote(self):
1328 req = Request("http://www.%70ython.org/")
1329 self.assertEqual("www.python.org", req.get_host())
1330
1331 def test_proxy(self):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001332 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001333 self.get.set_proxy("www.perl.org", "http")
Georg Brandlab91fde2009-08-13 08:51:18 +00001334 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001335 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1336 self.assertEqual("www.perl.org", self.get.get_host())
1337
Senthil Kumaran4c88db72010-08-08 11:30:58 +00001338 def test_wrapped_url(self):
1339 req = Request("<URL:http://www.python.org>")
1340 self.assertEqual("www.python.org", req.get_host())
1341
1342 def test_urlwith_fragment(self):
1343 req = Request("http://www.python.org/?qs=query#fragment=true")
1344 self.assertEqual("/?qs=query", req.get_selector())
1345 req = Request("http://www.python.org/#fun=true")
1346 self.assertEqual("/", req.get_selector())
1347
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001348
1349def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001350 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001351 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001352 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001353 tests = (TrivialTests,
1354 OpenerDirectorTests,
1355 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001356 MiscTests,
1357 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001358 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001359
1360if __name__ == "__main__":
1361 test_main(verbose=True)