blob: 14336705faa66cbf7376046b78eb0ee024d8c736 [file] [log] [blame]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002from test import support
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00003
Christian Heimes05e8be12008-02-23 18:30:17 +00004import os
Guido van Rossum34d19282007-08-09 01:03:29 +00005import io
Georg Brandlf78e02b2008-06-10 17:40:04 +00006import socket
Senthil Kumaran7bc0d872010-12-19 10:49:52 +00007import array
Jeremy Hyltone3e61042001-05-09 15:50:25 +00008
Jeremy Hylton1afc1692008-06-18 20:49:58 +00009import urllib.request
10from urllib.request import Request, OpenerDirector
Jeremy Hyltone3e61042001-05-09 15:50:25 +000011
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000012# XXX
13# Request
14# CacheFTPHandler (hard to write)
Thomas Wouters477c8d52006-05-27 19:21:47 +000015# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000016
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000017class TrivialTests(unittest.TestCase):
18 def test_trivial(self):
19 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000020
Jeremy Hylton1afc1692008-06-18 20:49:58 +000021 self.assertRaises(ValueError, urllib.request.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000022
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000023 # XXX Name hacking to get this to work on Windows.
Jeremy Hylton1afc1692008-06-18 20:49:58 +000024 fname = os.path.abspath(urllib.request.__file__).replace('\\', '/')
Senthil Kumarand587e302010-01-10 17:45:52 +000025
Senthil Kumarand587e302010-01-10 17:45:52 +000026 if os.name == 'nt':
27 file_url = "file:///%s" % fname
28 else:
29 file_url = "file://%s" % fname
30
Jeremy Hylton1afc1692008-06-18 20:49:58 +000031 f = urllib.request.urlopen(file_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000032
33 buf = f.read()
34 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000035
Georg Brandle1b13d22005-08-24 22:20:32 +000036 def test_parse_http_list(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000037 tests = [
38 ('a,b,c', ['a', 'b', 'c']),
39 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
40 ('a, b, "c", "d", "e,f", g, h',
41 ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
42 ('a="b\\"c", d="e\\,f", g="h\\\\i"',
43 ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
Georg Brandle1b13d22005-08-24 22:20:32 +000044 for string, list in tests:
Florent Xicluna419e3842010-08-08 16:16:07 +000045 self.assertEqual(urllib.request.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000046
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000047
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000048def test_request_headers_dict():
49 """
50 The Request.headers dictionary is not a documented interface. It should
51 stay that way, because the complete set of headers are only accessible
52 through the .get_header(), .has_header(), .header_items() interface.
53 However, .headers pre-dates those methods, and so real code will be using
54 the dictionary.
55
56 The introduction in 2.4 of those methods was a mistake for the same reason:
57 code that previously saw all (urllib2 user)-provided headers in .headers
58 now sees only a subset (and the function interface is ugly and incomplete).
59 A better change would have been to replace .headers dict with a dict
60 subclass (or UserDict.DictMixin instance?) that preserved the .headers
61 interface and also provided access to the "unredirected" headers. It's
62 probably too late to fix that, though.
63
64
65 Check .capitalize() case normalization:
66
67 >>> url = "http://example.com"
68 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
69 'blah'
70 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
71 'blah'
72
73 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
74 but that could be changed in future.
75
76 """
77
78def test_request_headers_methods():
79 """
80 Note the case normalization of header names here, to .capitalize()-case.
81 This should be preserved for backwards-compatibility. (In the HTTP case,
82 normalization to .title()-case is done by urllib2 before sending headers to
Georg Brandl24420152008-05-26 16:32:26 +000083 http.client).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000084
85 >>> url = "http://example.com"
86 >>> r = Request(url, headers={"Spam-eggs": "blah"})
87 >>> r.has_header("Spam-eggs")
88 True
89 >>> r.header_items()
90 [('Spam-eggs', 'blah')]
91 >>> r.add_header("Foo-Bar", "baz")
Guido van Rossumcc2b0162007-02-11 06:12:03 +000092 >>> items = sorted(r.header_items())
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000093 >>> items
94 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
95
96 Note that e.g. r.has_header("spam-EggS") is currently False, and
97 r.get_header("spam-EggS") returns None, but that could be changed in
98 future.
99
100 >>> r.has_header("Not-there")
101 False
Guido van Rossum7131f842007-02-09 20:13:25 +0000102 >>> print(r.get_header("Not-there"))
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000103 None
104 >>> r.get_header("Not-there", "default")
105 'default'
106
107 """
108
109
Thomas Wouters477c8d52006-05-27 19:21:47 +0000110def test_password_manager(self):
111 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000112 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000113 >>> add = mgr.add_password
114 >>> add("Some Realm", "http://example.com/", "joe", "password")
115 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
116 >>> add("c", "http://example.com/foo", "foo", "ni")
117 >>> add("c", "http://example.com/bar", "bar", "nini")
118 >>> add("b", "http://example.com/", "first", "blah")
119 >>> add("b", "http://example.com/", "second", "spam")
120 >>> add("a", "http://example.com", "1", "a")
121 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
122 >>> add("Some Realm", "d.example.com", "4", "d")
123 >>> add("Some Realm", "e.example.com:3128", "5", "e")
124
125 >>> mgr.find_user_password("Some Realm", "example.com")
126 ('joe', 'password')
127 >>> mgr.find_user_password("Some Realm", "http://example.com")
128 ('joe', 'password')
129 >>> mgr.find_user_password("Some Realm", "http://example.com/")
130 ('joe', 'password')
131 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
132 ('joe', 'password')
133 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
134 ('joe', 'password')
135 >>> mgr.find_user_password("c", "http://example.com/foo")
136 ('foo', 'ni')
137 >>> mgr.find_user_password("c", "http://example.com/bar")
138 ('bar', 'nini')
139
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000140 Actually, this is really undefined ATM
141## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000142
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000143## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
144## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000145
146 Use latest add_password() in case of conflict:
147
148 >>> mgr.find_user_password("b", "http://example.com/")
149 ('second', 'spam')
150
151 No special relationship between a.example.com and example.com:
152
153 >>> mgr.find_user_password("a", "http://example.com/")
154 ('1', 'a')
155 >>> mgr.find_user_password("a", "http://a.example.com/")
156 (None, None)
157
158 Ports:
159
160 >>> mgr.find_user_password("Some Realm", "c.example.com")
161 (None, None)
162 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
163 ('3', 'c')
164 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
165 ('3', 'c')
166 >>> mgr.find_user_password("Some Realm", "d.example.com")
167 ('4', 'd')
168 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
169 ('5', 'e')
170
171 """
172 pass
173
174
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000175def test_password_manager_default_port(self):
176 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000177 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000178 >>> add = mgr.add_password
179
180 The point to note here is that we can't guess the default port if there's
181 no scheme. This applies to both add_password and find_user_password.
182
183 >>> add("f", "http://g.example.com:80", "10", "j")
184 >>> add("g", "http://h.example.com", "11", "k")
185 >>> add("h", "i.example.com:80", "12", "l")
186 >>> add("i", "j.example.com", "13", "m")
187 >>> mgr.find_user_password("f", "g.example.com:100")
188 (None, None)
189 >>> mgr.find_user_password("f", "g.example.com:80")
190 ('10', 'j')
191 >>> mgr.find_user_password("f", "g.example.com")
192 (None, None)
193 >>> mgr.find_user_password("f", "http://g.example.com:100")
194 (None, None)
195 >>> mgr.find_user_password("f", "http://g.example.com:80")
196 ('10', 'j')
197 >>> mgr.find_user_password("f", "http://g.example.com")
198 ('10', 'j')
199 >>> mgr.find_user_password("g", "h.example.com")
200 ('11', 'k')
201 >>> mgr.find_user_password("g", "h.example.com:80")
202 ('11', 'k')
203 >>> mgr.find_user_password("g", "http://h.example.com:80")
204 ('11', 'k')
205 >>> mgr.find_user_password("h", "i.example.com")
206 (None, None)
207 >>> mgr.find_user_password("h", "i.example.com:80")
208 ('12', 'l')
209 >>> mgr.find_user_password("h", "http://i.example.com:80")
210 ('12', 'l')
211 >>> mgr.find_user_password("i", "j.example.com")
212 ('13', 'm')
213 >>> mgr.find_user_password("i", "j.example.com:80")
214 (None, None)
215 >>> mgr.find_user_password("i", "http://j.example.com")
216 ('13', 'm')
217 >>> mgr.find_user_password("i", "http://j.example.com:80")
218 (None, None)
219
220 """
221
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000222class MockOpener:
223 addheaders = []
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000224 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
225 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000226 def error(self, proto, *args):
227 self.proto, self.args = proto, args
228
229class MockFile:
230 def read(self, count=None): pass
231 def readline(self, count=None): pass
232 def close(self): pass
233
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000234class MockHeaders(dict):
235 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000236 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000237
Guido van Rossum34d19282007-08-09 01:03:29 +0000238class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000239 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000240 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000241 self.code, self.msg, self.headers, self.url = code, msg, headers, url
242 def info(self):
243 return self.headers
244 def geturl(self):
245 return self.url
246
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000247class MockCookieJar:
248 def add_cookie_header(self, request):
249 self.ach_req = request
250 def extract_cookies(self, response, request):
251 self.ec_req, self.ec_r = request, response
252
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000253class FakeMethod:
254 def __init__(self, meth_name, action, handle):
255 self.meth_name = meth_name
256 self.handle = handle
257 self.action = action
258 def __call__(self, *args):
259 return self.handle(self.meth_name, self.action, *args)
260
Senthil Kumaran47fff872009-12-20 07:10:31 +0000261class MockHTTPResponse(io.IOBase):
262 def __init__(self, fp, msg, status, reason):
263 self.fp = fp
264 self.msg = msg
265 self.status = status
266 self.reason = reason
267 self.code = 200
268
269 def read(self):
270 return ''
271
272 def info(self):
273 return {}
274
275 def geturl(self):
276 return self.url
277
278
279class MockHTTPClass:
280 def __init__(self):
281 self.level = 0
282 self.req_headers = []
283 self.data = None
284 self.raise_on_endheaders = False
285 self._tunnel_headers = {}
286
287 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
288 self.host = host
289 self.timeout = timeout
290 return self
291
292 def set_debuglevel(self, level):
293 self.level = level
294
295 def set_tunnel(self, host, port=None, headers=None):
296 self._tunnel_host = host
297 self._tunnel_port = port
298 if headers:
299 self._tunnel_headers = headers
300 else:
301 self._tunnel_headers.clear()
302
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000303 def request(self, method, url, body=None, headers=None):
Senthil Kumaran47fff872009-12-20 07:10:31 +0000304 self.method = method
305 self.selector = url
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000306 if headers is not None:
307 self.req_headers += headers.items()
Senthil Kumaran47fff872009-12-20 07:10:31 +0000308 self.req_headers.sort()
309 if body:
310 self.data = body
311 if self.raise_on_endheaders:
312 import socket
313 raise socket.error()
314 def getresponse(self):
315 return MockHTTPResponse(MockFile(), {}, 200, "OK")
316
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000317class MockHandler:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000318 # useful for testing handler machinery
319 # see add_ordered_mock_handlers() docstring
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000320 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000321 def __init__(self, methods):
322 self._define_methods(methods)
323 def _define_methods(self, methods):
324 for spec in methods:
325 if len(spec) == 2: name, action = spec
326 else: name, action = spec, None
327 meth = FakeMethod(name, action, self.handle)
328 setattr(self.__class__, name, meth)
329 def handle(self, fn_name, action, *args, **kwds):
330 self.parent.calls.append((self, fn_name, args, kwds))
331 if action is None:
332 return None
333 elif action == "return self":
334 return self
335 elif action == "return response":
336 res = MockResponse(200, "OK", {}, "")
337 return res
338 elif action == "return request":
339 return Request("http://blah/")
340 elif action.startswith("error"):
341 code = action[action.rfind(" ")+1:]
342 try:
343 code = int(code)
344 except ValueError:
345 pass
346 res = MockResponse(200, "OK", {}, "")
347 return self.parent.error("http", args[0], res, code, "", {})
348 elif action == "raise":
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000349 raise urllib.error.URLError("blah")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000350 assert False
351 def close(self): pass
352 def add_parent(self, parent):
353 self.parent = parent
354 self.parent.calls = []
355 def __lt__(self, other):
356 if not hasattr(other, "handler_order"):
357 # No handler_order, leave in original order. Yuck.
358 return True
359 return self.handler_order < other.handler_order
360
361def add_ordered_mock_handlers(opener, meth_spec):
362 """Create MockHandlers and add them to an OpenerDirector.
363
364 meth_spec: list of lists of tuples and strings defining methods to define
365 on handlers. eg:
366
367 [["http_error", "ftp_open"], ["http_open"]]
368
369 defines methods .http_error() and .ftp_open() on one handler, and
370 .http_open() on another. These methods just record their arguments and
371 return None. Using a tuple instead of a string causes the method to
372 perform some action (see MockHandler.handle()), eg:
373
374 [["http_error"], [("http_open", "return request")]]
375
376 defines .http_error() on one handler (which simply returns None), and
377 .http_open() on another handler, which returns a Request object.
378
379 """
380 handlers = []
381 count = 0
382 for meths in meth_spec:
383 class MockHandlerSubclass(MockHandler): pass
384 h = MockHandlerSubclass(meths)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000385 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000386 h.add_parent(opener)
387 count = count + 1
388 handlers.append(h)
389 opener.add_handler(h)
390 return handlers
391
Thomas Wouters477c8d52006-05-27 19:21:47 +0000392def build_test_opener(*handler_instances):
393 opener = OpenerDirector()
394 for h in handler_instances:
395 opener.add_handler(h)
396 return opener
397
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000398class MockHTTPHandler(urllib.request.BaseHandler):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000399 # useful for testing redirections and auth
400 # sends supplied headers and code as first response
401 # sends 200 OK as second response
402 def __init__(self, code, headers):
403 self.code = code
404 self.headers = headers
405 self.reset()
406 def reset(self):
407 self._count = 0
408 self.requests = []
409 def http_open(self, req):
Barry Warsaw820c1202008-06-12 04:06:45 +0000410 import email, http.client, copy
Guido van Rossum34d19282007-08-09 01:03:29 +0000411 from io import StringIO
Thomas Wouters477c8d52006-05-27 19:21:47 +0000412 self.requests.append(copy.deepcopy(req))
413 if self._count == 0:
414 self._count = self._count + 1
Georg Brandl24420152008-05-26 16:32:26 +0000415 name = http.client.responses[self.code]
Barry Warsaw820c1202008-06-12 04:06:45 +0000416 msg = email.message_from_string(self.headers)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000417 return self.parent.error(
418 "http", req, MockFile(), self.code, name, msg)
419 else:
420 self.req = req
Barry Warsaw820c1202008-06-12 04:06:45 +0000421 msg = email.message_from_string("\r\n\r\n")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000422 return MockResponse(200, "OK", msg, "", req.get_full_url())
423
Senthil Kumaran47fff872009-12-20 07:10:31 +0000424class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
425 # Useful for testing the Proxy-Authorization request by verifying the
426 # properties of httpcon
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000427
428 def __init__(self):
429 urllib.request.AbstractHTTPHandler.__init__(self)
430 self.httpconn = MockHTTPClass()
431
Senthil Kumaran47fff872009-12-20 07:10:31 +0000432 def https_open(self, req):
433 return self.do_open(self.httpconn, req)
434
Thomas Wouters477c8d52006-05-27 19:21:47 +0000435class MockPasswordManager:
436 def add_password(self, realm, uri, user, password):
437 self.realm = realm
438 self.url = uri
439 self.user = user
440 self.password = password
441 def find_user_password(self, realm, authuri):
442 self.target_realm = realm
443 self.target_url = authuri
444 return self.user, self.password
445
446
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000447class OpenerDirectorTests(unittest.TestCase):
448
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000449 def test_add_non_handler(self):
450 class NonHandler(object):
451 pass
452 self.assertRaises(TypeError,
453 OpenerDirector().add_handler, NonHandler())
454
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000455 def test_badly_named_methods(self):
456 # test work-around for three methods that accidentally follow the
457 # naming conventions for handler methods
458 # (*_open() / *_request() / *_response())
459
460 # These used to call the accidentally-named methods, causing a
461 # TypeError in real code; here, returning self from these mock
462 # methods would either cause no exception, or AttributeError.
463
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000464 from urllib.error import URLError
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000465
466 o = OpenerDirector()
467 meth_spec = [
468 [("do_open", "return self"), ("proxy_open", "return self")],
469 [("redirect_request", "return self")],
470 ]
471 handlers = add_ordered_mock_handlers(o, meth_spec)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000472 o.add_handler(urllib.request.UnknownHandler())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000473 for scheme in "do", "proxy", "redirect":
474 self.assertRaises(URLError, o.open, scheme+"://example.com/")
475
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000476 def test_handled(self):
477 # handler returning non-None means no more handlers will be called
478 o = OpenerDirector()
479 meth_spec = [
480 ["http_open", "ftp_open", "http_error_302"],
481 ["ftp_open"],
482 [("http_open", "return self")],
483 [("http_open", "return self")],
484 ]
485 handlers = add_ordered_mock_handlers(o, meth_spec)
486
487 req = Request("http://example.com/")
488 r = o.open(req)
489 # Second .http_open() gets called, third doesn't, since second returned
490 # non-None. Handlers without .http_open() never get any methods called
491 # on them.
492 # In fact, second mock handler defining .http_open() returns self
493 # (instead of response), which becomes the OpenerDirector's return
494 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000495 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000496 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
497 for expected, got in zip(calls, o.calls):
498 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000499 self.assertEqual((handler, name), expected)
500 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000501
502 def test_handler_order(self):
503 o = OpenerDirector()
504 handlers = []
505 for meths, handler_order in [
506 ([("http_open", "return self")], 500),
507 (["http_open"], 0),
508 ]:
509 class MockHandlerSubclass(MockHandler): pass
510 h = MockHandlerSubclass(meths)
511 h.handler_order = handler_order
512 handlers.append(h)
513 o.add_handler(h)
514
515 r = o.open("http://example.com/")
516 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000517 self.assertEqual(o.calls[0][0], handlers[1])
518 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000519
520 def test_raise(self):
521 # raising URLError stops processing of request
522 o = OpenerDirector()
523 meth_spec = [
524 [("http_open", "raise")],
525 [("http_open", "return self")],
526 ]
527 handlers = add_ordered_mock_handlers(o, meth_spec)
528
529 req = Request("http://example.com/")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000530 self.assertRaises(urllib.error.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000531 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000532
533## def test_error(self):
534## # XXX this doesn't actually seem to be used in standard library,
535## # but should really be tested anyway...
536
537 def test_http_error(self):
538 # XXX http_error_default
539 # http errors are a special case
540 o = OpenerDirector()
541 meth_spec = [
542 [("http_open", "error 302")],
543 [("http_error_400", "raise"), "http_open"],
544 [("http_error_302", "return response"), "http_error_303",
545 "http_error"],
546 [("http_error_302")],
547 ]
548 handlers = add_ordered_mock_handlers(o, meth_spec)
549
550 class Unknown:
551 def __eq__(self, other): return True
552
553 req = Request("http://example.com/")
554 r = o.open(req)
555 assert len(o.calls) == 2
556 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000557 (handlers[2], "http_error_302",
558 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000559 for expected, got in zip(calls, o.calls):
560 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000561 self.assertEqual((handler, method_name), got[:2])
562 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000563
564 def test_processors(self):
565 # *_request / *_response methods get called appropriately
566 o = OpenerDirector()
567 meth_spec = [
568 [("http_request", "return request"),
569 ("http_response", "return response")],
570 [("http_request", "return request"),
571 ("http_response", "return response")],
572 ]
573 handlers = add_ordered_mock_handlers(o, meth_spec)
574
575 req = Request("http://example.com/")
576 r = o.open(req)
577 # processor methods are called on *all* handlers that define them,
578 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000579 calls = [
580 (handlers[0], "http_request"), (handlers[1], "http_request"),
581 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000582
583 for i, (handler, name, args, kwds) in enumerate(o.calls):
584 if i < 2:
585 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000586 self.assertEqual((handler, name), calls[i])
587 self.assertEqual(len(args), 1)
Ezio Melottie9615932010-01-24 19:26:24 +0000588 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000589 else:
590 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000591 self.assertEqual((handler, name), calls[i])
592 self.assertEqual(len(args), 2)
Ezio Melottie9615932010-01-24 19:26:24 +0000593 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000594 # response from opener.open is None, because there's no
595 # handler that defines http_open to handle it
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000596 self.assertTrue(args[1] is None or
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000597 isinstance(args[1], MockResponse))
598
599
Tim Peters58eb11c2004-01-18 20:29:55 +0000600def sanepathname2url(path):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000601 try:
602 path.encode("utf8")
603 except UnicodeEncodeError:
604 raise unittest.SkipTest("path is not encodable to utf8")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000605 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000606 if os.name == "nt" and urlpath.startswith("///"):
607 urlpath = urlpath[2:]
608 # XXX don't ask me about the mac...
609 return urlpath
610
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000611class HandlerTests(unittest.TestCase):
612
613 def test_ftp(self):
614 class MockFTPWrapper:
615 def __init__(self, data): self.data = data
616 def retrfile(self, filename, filetype):
617 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000618 return io.StringIO(self.data), len(self.data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000619
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000620 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000621 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000622 def connect_ftp(self, user, passwd, host, port, dirs,
623 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000624 self.user, self.passwd = user, passwd
625 self.host, self.port = host, port
626 self.dirs = dirs
627 self.ftpwrapper = MockFTPWrapper(self.data)
628 return self.ftpwrapper
629
Georg Brandlf78e02b2008-06-10 17:40:04 +0000630 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000631 data = "rheum rhaponicum"
632 h = NullFTPHandler(data)
633 o = h.parent = MockOpener()
634
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000635 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000636 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000637 "localhost", ftplib.FTP_PORT, "", "", "I",
638 ["foo", "bar"], "baz.html", "text/html"),
639 ("ftp://parrot@localhost/foo/bar/baz.html",
640 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
641 ["foo", "bar"], "baz.html", "text/html"),
642 ("ftp://%25parrot@localhost/foo/bar/baz.html",
643 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
644 ["foo", "bar"], "baz.html", "text/html"),
645 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
646 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000647 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000648 ("ftp://localhost:80/foo/bar/",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000649 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000650 ["foo", "bar"], "", None),
651 ("ftp://localhost/baz.gif;type=a",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000652 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000653 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000654 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000655 req = Request(url)
656 req.timeout = None
657 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000658 # ftp authentication not yet implemented by FTPHandler
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000659 self.assertEqual(h.user, user)
660 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000661 self.assertEqual(h.host, socket.gethostbyname(host))
662 self.assertEqual(h.port, port)
663 self.assertEqual(h.dirs, dirs)
664 self.assertEqual(h.ftpwrapper.filename, filename)
665 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000666 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000667 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000668 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000669
670 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000671 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000672 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000673 o = h.parent = MockOpener()
674
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000675 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000676 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000677 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000678 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000679 "file://localhost%s" % urlpath,
680 "file://%s" % urlpath,
681 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000682 ]
683 try:
684 localaddr = socket.gethostbyname(socket.gethostname())
685 except socket.gaierror:
686 localaddr = ''
687 if localaddr:
688 urls.append("file://%s%s" % (localaddr, urlpath))
689
690 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000691 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000692 try:
693 try:
694 f.write(towrite)
695 finally:
696 f.close()
697
698 r = h.file_open(Request(url))
699 try:
700 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000701 headers = r.info()
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000702 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000703 finally:
704 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000705 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000706 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000707 finally:
708 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000709 self.assertEqual(data, towrite)
710 self.assertEqual(headers["Content-type"], "text/plain")
711 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000712 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000713 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000714
715 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000716 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000717 "file:///file_does_not_exist.txt",
718 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
719 os.getcwd(), TESTFN),
720 "file://somerandomhost.ontheinternet.com%s/%s" %
721 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000722 ]:
723 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000724 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000725 try:
726 f.write(towrite)
727 finally:
728 f.close()
729
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000730 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000731 h.file_open, Request(url))
732 finally:
733 os.remove(TESTFN)
734
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000735 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000736 o = h.parent = MockOpener()
737 # XXXX why does // mean ftp (and /// mean not ftp!), and where
738 # is file: scheme specified? I think this is really a bug, and
739 # what was intended was to distinguish between URLs like:
740 # file:/blah.txt (a file)
741 # file://localhost/blah.txt (a file)
742 # file:///blah.txt (a file)
743 # file://ftp.example.com/blah.txt (an ftp URL)
744 for url, ftp in [
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000745 ("file://ftp.example.com//foo.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000746 ("file://ftp.example.com///foo.txt", False),
747# XXXX bug: fails with OSError, should be URLError
748 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000749 ("file://somehost//foo/something.txt", False),
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000750 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000751 ]:
752 req = Request(url)
753 try:
754 h.file_open(req)
755 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000756 except (urllib.error.URLError, OSError):
Florent Xicluna419e3842010-08-08 16:16:07 +0000757 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000758 else:
Florent Xicluna419e3842010-08-08 16:16:07 +0000759 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000760 self.assertEqual(req.type, "ftp")
Łukasz Langad7e81cc2011-01-09 18:18:53 +0000761 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000762
763 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000764
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000765 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000766 o = h.parent = MockOpener()
767
768 url = "http://example.com/"
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000769 for method, data in [("GET", None), ("POST", b"blah")]:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000770 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000771 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000772 req.add_unredirected_header("Spam", "eggs")
773 http = MockHTTPClass()
774 r = h.do_open(http, req)
775
776 # result attributes
777 r.read; r.readline # wrapped MockFile methods
778 r.info; r.geturl # addinfourl methods
779 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
780 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000781 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000782 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000783
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000784 self.assertEqual(http.host, "example.com")
785 self.assertEqual(http.level, 0)
786 self.assertEqual(http.method, method)
787 self.assertEqual(http.selector, "/")
788 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000789 [("Connection", "close"),
790 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000791 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000792
793 # check socket.error converted to URLError
794 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000795 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000796
Senthil Kumaran29333122011-02-11 11:25:47 +0000797 # Check for TypeError on POST data which is str.
798 req = Request("http://example.com/","badpost")
799 self.assertRaises(TypeError, h.do_request_, req)
800
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000801 # check adding of standard headers
802 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000803 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000804 req = Request("http://example.com/", data)
805 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000806 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000807 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000808 self.assertNotIn("Content-length", req.unredirected_hdrs)
809 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000810 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000811 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
812 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000813 "application/x-www-form-urlencoded")
814 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000815 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
816 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000817
818 # don't clobber existing headers
819 req.add_unredirected_header("Content-length", "foo")
820 req.add_unredirected_header("Content-type", "bar")
821 req.add_unredirected_header("Host", "baz")
822 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000823 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000824 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
825 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000826 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
827 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000828
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000829 # Check iterable body support
830 def iterable_body():
831 yield b"one"
832 yield b"two"
833 yield b"three"
834
835 for headers in {}, {"Content-Length": 11}:
836 req = Request("http://example.com/", iterable_body(), headers)
837 if not headers:
838 # Having an iterable body without a Content-Length should
839 # raise an exception
840 self.assertRaises(ValueError, h.do_request_, req)
841 else:
842 newreq = h.do_request_(req)
843
Senthil Kumaran29333122011-02-11 11:25:47 +0000844 # A file object.
845 # Test only Content-Length attribute of request.
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000846
Senthil Kumaran29333122011-02-11 11:25:47 +0000847 file_obj = io.BytesIO()
848 file_obj.write(b"Something\nSomething\nSomething\n")
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000849
850 for headers in {}, {"Content-Length": 30}:
851 req = Request("http://example.com/", file_obj, headers)
852 if not headers:
853 # Having an iterable body without a Content-Length should
854 # raise an exception
855 self.assertRaises(ValueError, h.do_request_, req)
856 else:
857 newreq = h.do_request_(req)
858 self.assertEqual(int(newreq.get_header('Content-length')),30)
859
860 file_obj.close()
861
862 # array.array Iterable - Content Length is calculated
863
864 iterable_array = array.array("I",[1,2,3,4])
865
866 for headers in {}, {"Content-Length": 16}:
867 req = Request("http://example.com/", iterable_array, headers)
868 newreq = h.do_request_(req)
869 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000870
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000871 def test_http_doubleslash(self):
872 # Checks the presence of any unnecessary double slash in url does not
873 # break anything. Previously, a double slash directly after the host
874 # could could cause incorrect parsing.
875 h = urllib.request.AbstractHTTPHandler()
876 o = h.parent = MockOpener()
877
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000878 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000879 ds_urls = [
880 "http://example.com/foo/bar/baz.html",
881 "http://example.com//foo/bar/baz.html",
882 "http://example.com/foo//bar/baz.html",
883 "http://example.com/foo/bar//baz.html"
884 ]
885
886 for ds_url in ds_urls:
887 ds_req = Request(ds_url, data)
888
889 # Check whether host is determined correctly if there is no proxy
890 np_ds_req = h.do_request_(ds_req)
891 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
892
893 # Check whether host is determined correctly if there is a proxy
894 ds_req.set_proxy("someproxy:3128",None)
895 p_ds_req = h.do_request_(ds_req)
896 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
897
Senthil Kumaranc2958622010-11-22 04:48:26 +0000898 def test_fixpath_in_weirdurls(self):
899 # Issue4493: urllib2 to supply '/' when to urls where path does not
900 # start with'/'
901
902 h = urllib.request.AbstractHTTPHandler()
903 o = h.parent = MockOpener()
904
905 weird_url = 'http://www.python.org?getspam'
906 req = Request(weird_url)
907 newreq = h.do_request_(req)
908 self.assertEqual(newreq.host,'www.python.org')
909 self.assertEqual(newreq.selector,'/?getspam')
910
911 url_without_path = 'http://www.python.org'
912 req = Request(url_without_path)
913 newreq = h.do_request_(req)
914 self.assertEqual(newreq.host,'www.python.org')
915 self.assertEqual(newreq.selector,'')
916
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000917
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000918 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000919 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000920 o = h.parent = MockOpener()
921
922 url = "http://example.com/"
923 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000924 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000925 r = MockResponse(200, "OK", {}, "", url)
926 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000927 self.assertIs(r, newr)
928 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000929 r = MockResponse(202, "Accepted", {}, "", url)
930 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000931 self.assertIs(r, newr)
932 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000933 r = MockResponse(206, "Partial content", {}, "", url)
934 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000935 self.assertIs(r, newr)
936 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000937 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000938 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000939 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000940 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000941 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000942
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000943 def test_cookies(self):
944 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000945 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000946 o = h.parent = MockOpener()
947
948 req = Request("http://example.com/")
949 r = MockResponse(200, "OK", {}, "")
950 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000951 self.assertIs(cj.ach_req, req)
952 self.assertIs(cj.ach_req, newreq)
953 self.assertEqual(req.get_origin_req_host(), "example.com")
954 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000955 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000956 self.assertIs(cj.ec_req, req)
957 self.assertIs(cj.ec_r, r)
958 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000959
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000960 def test_redirect(self):
961 from_url = "http://example.com/a.html"
962 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000963 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000964 o = h.parent = MockOpener()
965
966 # ordinary redirect behaviour
967 for code in 301, 302, 303, 307:
968 for data in None, "blah\nblah\n":
969 method = getattr(h, "http_error_%s" % code)
970 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000971 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000972 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000973 if data is not None:
974 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000975 req.add_unredirected_header("Spam", "spam")
976 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000977 method(req, MockFile(), code, "Blah",
978 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000979 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000980 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000981 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000982 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000983 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000984 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000985 except AttributeError:
Florent Xicluna419e3842010-08-08 16:16:07 +0000986 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +0000987
988 # now it's a GET, there should not be headers regarding content
989 # (possibly dragged from before being a POST)
990 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +0000991 self.assertNotIn("content-length", headers)
992 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +0000993
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000994 self.assertEqual(o.req.headers["Nonsense"],
995 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +0000996 self.assertNotIn("Spam", o.req.headers)
997 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000998
999 # loop detection
1000 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001001 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001002 def redirect(h, req, url=to_url):
1003 h.http_error_302(req, MockFile(), 302, "Blah",
1004 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001005 # Note that the *original* request shares the same record of
1006 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001007
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001008 # detect infinite loop redirect of a URL to itself
1009 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001010 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001011 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001012 try:
1013 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001014 redirect(h, req, "http://example.com/")
1015 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001016 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001017 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001018 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001019
1020 # detect endless non-repeating chain of redirects
1021 req = Request(from_url, origin_req_host="example.com")
1022 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001023 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001024 try:
1025 while 1:
1026 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001027 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001028 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001029 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001030 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001031
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001032 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001033 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001034 from http.cookiejar import CookieJar
1035 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001036
1037 cj = CookieJar()
1038 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001039 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001040 hdeh = urllib.request.HTTPDefaultErrorHandler()
1041 hrh = urllib.request.HTTPRedirectHandler()
1042 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001043 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001044 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001045 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001046
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001047 def test_proxy(self):
1048 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001049 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001050 o.add_handler(ph)
1051 meth_spec = [
1052 [("http_open", "return response")]
1053 ]
1054 handlers = add_ordered_mock_handlers(o, meth_spec)
1055
1056 req = Request("http://acme.example.com/")
1057 self.assertEqual(req.get_host(), "acme.example.com")
1058 r = o.open(req)
1059 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1060
1061 self.assertEqual([(handlers[0], "http_open")],
1062 [tup[0:2] for tup in o.calls])
1063
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001064 def test_proxy_no_proxy(self):
1065 os.environ['no_proxy'] = 'python.org'
1066 o = OpenerDirector()
1067 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1068 o.add_handler(ph)
1069 req = Request("http://www.perl.org/")
1070 self.assertEqual(req.get_host(), "www.perl.org")
1071 r = o.open(req)
1072 self.assertEqual(req.get_host(), "proxy.example.com")
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
1079
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +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 Kumaran47fff872009-12-20 07:10:31 +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.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001111 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001112 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001113 self.assertIn(("User-Agent","Grail"),
1114 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001115 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 Kumaran97f0c6b2009-07-25 04:24:38 +00001118
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001119 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001120 opener = OpenerDirector()
1121 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001122 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001123 realm = "ACME Widget Store"
1124 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001125 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1126 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001127 opener.add_handler(auth_handler)
1128 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001129 self._test_basic_auth(opener, auth_handler, "Authorization",
1130 realm, http_handler, password_manager,
1131 "http://acme.example.com/protected",
1132 "http://acme.example.com/protected",
1133 )
1134
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001135 def test_basic_auth_with_single_quoted_realm(self):
1136 self.test_basic_auth(quote_char="'")
1137
Thomas Wouters477c8d52006-05-27 19:21:47 +00001138 def test_proxy_basic_auth(self):
1139 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001140 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001141 opener.add_handler(ph)
1142 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001143 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001144 realm = "ACME Networks"
1145 http_handler = MockHTTPHandler(
1146 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001147 opener.add_handler(auth_handler)
1148 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001149 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001150 realm, http_handler, password_manager,
1151 "http://acme.example.com:3128/protected",
1152 "proxy.example.com:3128",
1153 )
1154
1155 def test_basic_and_digest_auth_handlers(self):
1156 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1157 # response (http://python.org/sf/1479302), where it should instead
1158 # return None to allow another handler (especially
1159 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001160
1161 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1162 # try digest first (since it's the strongest auth scheme), so we record
1163 # order of calls here to check digest comes first:
1164 class RecordingOpenerDirector(OpenerDirector):
1165 def __init__(self):
1166 OpenerDirector.__init__(self)
1167 self.recorded = []
1168 def record(self, info):
1169 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001170 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001171 def http_error_401(self, *args, **kwds):
1172 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001173 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001174 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001175 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001176 def http_error_401(self, *args, **kwds):
1177 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001178 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001179 *args, **kwds)
1180
1181 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001182 password_manager = MockPasswordManager()
1183 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001184 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001185 realm = "ACME Networks"
1186 http_handler = MockHTTPHandler(
1187 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001188 opener.add_handler(basic_handler)
1189 opener.add_handler(digest_handler)
1190 opener.add_handler(http_handler)
1191
1192 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001193 self._test_basic_auth(opener, basic_handler, "Authorization",
1194 realm, http_handler, password_manager,
1195 "http://acme.example.com/protected",
1196 "http://acme.example.com/protected",
1197 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001198 # check digest was tried before basic (twice, because
1199 # _test_basic_auth called .open() twice)
1200 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001201
1202 def _test_basic_auth(self, opener, auth_handler, auth_header,
1203 realm, http_handler, password_manager,
1204 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001205 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001206 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001207
1208 # .add_password() fed through to password manager
1209 auth_handler.add_password(realm, request_url, user, password)
1210 self.assertEqual(realm, password_manager.realm)
1211 self.assertEqual(request_url, password_manager.url)
1212 self.assertEqual(user, password_manager.user)
1213 self.assertEqual(password, password_manager.password)
1214
1215 r = opener.open(request_url)
1216
1217 # should have asked the password manager for the username/password
1218 self.assertEqual(password_manager.target_realm, realm)
1219 self.assertEqual(password_manager.target_url, protected_url)
1220
1221 # expect one request without authorization, then one with
1222 self.assertEqual(len(http_handler.requests), 2)
1223 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001224 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001225 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001226 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001227 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1228 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001229 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1230 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001231 # if the password manager can't find a password, the handler won't
1232 # handle the HTTP auth error
1233 password_manager.user = password_manager.password = None
1234 http_handler.reset()
1235 r = opener.open(request_url)
1236 self.assertEqual(len(http_handler.requests), 1)
1237 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1238
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001239class MiscTests(unittest.TestCase):
1240
1241 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001242 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1243 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001244 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001245 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001246 def bar_open(self): pass
1247
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001248 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001249
1250 o = build_opener(FooHandler, BarHandler)
1251 self.opener_has_handler(o, FooHandler)
1252 self.opener_has_handler(o, BarHandler)
1253
1254 # can take a mix of classes and instances
1255 o = build_opener(FooHandler, BarHandler())
1256 self.opener_has_handler(o, FooHandler)
1257 self.opener_has_handler(o, BarHandler)
1258
1259 # subclasses of default handlers override default handlers
1260 o = build_opener(MyHTTPHandler)
1261 self.opener_has_handler(o, MyHTTPHandler)
1262
1263 # a particular case of overriding: default handlers can be passed
1264 # in explicitly
1265 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001266 self.opener_has_handler(o, urllib.request.HTTPHandler)
1267 o = build_opener(urllib.request.HTTPHandler)
1268 self.opener_has_handler(o, urllib.request.HTTPHandler)
1269 o = build_opener(urllib.request.HTTPHandler())
1270 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001271
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001272 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001273 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001274 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1275 self.opener_has_handler(o, MyHTTPHandler)
1276 self.opener_has_handler(o, MyOtherHTTPHandler)
1277
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001278 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001279 self.assertTrue(any(h.__class__ == handler_class
1280 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001281
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001282class RequestTests(unittest.TestCase):
1283
1284 def setUp(self):
1285 self.get = Request("http://www.python.org/~jeremy/")
1286 self.post = Request("http://www.python.org/~jeremy/",
1287 "data",
1288 headers={"X-Test": "test"})
1289
1290 def test_method(self):
1291 self.assertEqual("POST", self.post.get_method())
1292 self.assertEqual("GET", self.get.get_method())
1293
1294 def test_add_data(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001295 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001296 self.assertEqual("GET", self.get.get_method())
1297 self.get.add_data("spam")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001298 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001299 self.assertEqual("POST", self.get.get_method())
1300
1301 def test_get_full_url(self):
1302 self.assertEqual("http://www.python.org/~jeremy/",
1303 self.get.get_full_url())
1304
1305 def test_selector(self):
1306 self.assertEqual("/~jeremy/", self.get.get_selector())
1307 req = Request("http://www.python.org/")
1308 self.assertEqual("/", req.get_selector())
1309
1310 def test_get_type(self):
1311 self.assertEqual("http", self.get.get_type())
1312
1313 def test_get_host(self):
1314 self.assertEqual("www.python.org", self.get.get_host())
1315
1316 def test_get_host_unquote(self):
1317 req = Request("http://www.%70ython.org/")
1318 self.assertEqual("www.python.org", req.get_host())
1319
1320 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001321 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001322 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001323 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001324 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1325 self.assertEqual("www.perl.org", self.get.get_host())
1326
Senthil Kumarand95cc752010-08-08 11:27:53 +00001327 def test_wrapped_url(self):
1328 req = Request("<URL:http://www.python.org>")
1329 self.assertEqual("www.python.org", req.get_host())
1330
1331 def test_urlwith_fragment(self):
1332 req = Request("http://www.python.org/?qs=query#fragment=true")
1333 self.assertEqual("/?qs=query", req.get_selector())
1334 req = Request("http://www.python.org/#fun=true")
1335 self.assertEqual("/", req.get_selector())
1336
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001337
1338def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001339 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001340 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001341 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001342 tests = (TrivialTests,
1343 OpenerDirectorTests,
1344 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001345 MiscTests,
1346 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001347 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001348
1349if __name__ == "__main__":
1350 test_main(verbose=True)