blob: 1ce88af80e2d2f8de07c5430094524518a2c07ca [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")
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000761 self.assertEqual(req.type is "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
797 # check adding of standard headers
798 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000799 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000800 req = Request("http://example.com/", data)
801 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000802 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000803 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000804 self.assertNotIn("Content-length", req.unredirected_hdrs)
805 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000806 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000807 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
808 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000809 "application/x-www-form-urlencoded")
810 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000811 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
812 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000813
814 # don't clobber existing headers
815 req.add_unredirected_header("Content-length", "foo")
816 req.add_unredirected_header("Content-type", "bar")
817 req.add_unredirected_header("Host", "baz")
818 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000819 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000820 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
821 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000822 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
823 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000824
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000825 # Check iterable body support
826 def iterable_body():
827 yield b"one"
828 yield b"two"
829 yield b"three"
830
831 for headers in {}, {"Content-Length": 11}:
832 req = Request("http://example.com/", iterable_body(), headers)
833 if not headers:
834 # Having an iterable body without a Content-Length should
835 # raise an exception
836 self.assertRaises(ValueError, h.do_request_, req)
837 else:
838 newreq = h.do_request_(req)
839
840 # A file object
841
842 """
843 file_obj = io.StringIO()
844 file_obj.write("Something\nSomething\nSomething\n")
845
846 for headers in {}, {"Content-Length": 30}:
847 req = Request("http://example.com/", file_obj, headers)
848 if not headers:
849 # Having an iterable body without a Content-Length should
850 # raise an exception
851 self.assertRaises(ValueError, h.do_request_, req)
852 else:
853 newreq = h.do_request_(req)
854 self.assertEqual(int(newreq.get_header('Content-length')),30)
855
856 file_obj.close()
857
858 # array.array Iterable - Content Length is calculated
859
860 iterable_array = array.array("I",[1,2,3,4])
861
862 for headers in {}, {"Content-Length": 16}:
863 req = Request("http://example.com/", iterable_array, headers)
864 newreq = h.do_request_(req)
865 self.assertEqual(int(newreq.get_header('Content-length')),16)
866 """
867
868
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000869 def test_http_doubleslash(self):
870 # Checks the presence of any unnecessary double slash in url does not
871 # break anything. Previously, a double slash directly after the host
872 # could could cause incorrect parsing.
873 h = urllib.request.AbstractHTTPHandler()
874 o = h.parent = MockOpener()
875
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000876 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000877 ds_urls = [
878 "http://example.com/foo/bar/baz.html",
879 "http://example.com//foo/bar/baz.html",
880 "http://example.com/foo//bar/baz.html",
881 "http://example.com/foo/bar//baz.html"
882 ]
883
884 for ds_url in ds_urls:
885 ds_req = Request(ds_url, data)
886
887 # Check whether host is determined correctly if there is no proxy
888 np_ds_req = h.do_request_(ds_req)
889 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
890
891 # Check whether host is determined correctly if there is a proxy
892 ds_req.set_proxy("someproxy:3128",None)
893 p_ds_req = h.do_request_(ds_req)
894 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
895
Senthil Kumaranc2958622010-11-22 04:48:26 +0000896 def test_fixpath_in_weirdurls(self):
897 # Issue4493: urllib2 to supply '/' when to urls where path does not
898 # start with'/'
899
900 h = urllib.request.AbstractHTTPHandler()
901 o = h.parent = MockOpener()
902
903 weird_url = 'http://www.python.org?getspam'
904 req = Request(weird_url)
905 newreq = h.do_request_(req)
906 self.assertEqual(newreq.host,'www.python.org')
907 self.assertEqual(newreq.selector,'/?getspam')
908
909 url_without_path = 'http://www.python.org'
910 req = Request(url_without_path)
911 newreq = h.do_request_(req)
912 self.assertEqual(newreq.host,'www.python.org')
913 self.assertEqual(newreq.selector,'')
914
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000915
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000916 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000917 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000918 o = h.parent = MockOpener()
919
920 url = "http://example.com/"
921 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000922 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000923 r = MockResponse(200, "OK", {}, "", url)
924 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000925 self.assertIs(r, newr)
926 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000927 r = MockResponse(202, "Accepted", {}, "", url)
928 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000929 self.assertIs(r, newr)
930 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000931 r = MockResponse(206, "Partial content", {}, "", url)
932 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000933 self.assertIs(r, newr)
934 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000935 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000936 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000937 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000938 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000939 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000940
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000941 def test_cookies(self):
942 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000943 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000944 o = h.parent = MockOpener()
945
946 req = Request("http://example.com/")
947 r = MockResponse(200, "OK", {}, "")
948 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000949 self.assertIs(cj.ach_req, req)
950 self.assertIs(cj.ach_req, newreq)
951 self.assertEqual(req.get_origin_req_host(), "example.com")
952 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000953 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000954 self.assertIs(cj.ec_req, req)
955 self.assertIs(cj.ec_r, r)
956 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000957
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000958 def test_redirect(self):
959 from_url = "http://example.com/a.html"
960 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000961 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000962 o = h.parent = MockOpener()
963
964 # ordinary redirect behaviour
965 for code in 301, 302, 303, 307:
966 for data in None, "blah\nblah\n":
967 method = getattr(h, "http_error_%s" % code)
968 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000969 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000970 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000971 if data is not None:
972 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000973 req.add_unredirected_header("Spam", "spam")
974 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000975 method(req, MockFile(), code, "Blah",
976 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000977 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000978 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000979 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000980 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000981 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000982 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000983 except AttributeError:
Florent Xicluna419e3842010-08-08 16:16:07 +0000984 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +0000985
986 # now it's a GET, there should not be headers regarding content
987 # (possibly dragged from before being a POST)
988 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +0000989 self.assertNotIn("content-length", headers)
990 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +0000991
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000992 self.assertEqual(o.req.headers["Nonsense"],
993 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +0000994 self.assertNotIn("Spam", o.req.headers)
995 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000996
997 # loop detection
998 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000999 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001000 def redirect(h, req, url=to_url):
1001 h.http_error_302(req, MockFile(), 302, "Blah",
1002 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001003 # Note that the *original* request shares the same record of
1004 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001005
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001006 # detect infinite loop redirect of a URL to itself
1007 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001008 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001009 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001010 try:
1011 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001012 redirect(h, req, "http://example.com/")
1013 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001014 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001015 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001016 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001017
1018 # detect endless non-repeating chain of redirects
1019 req = Request(from_url, origin_req_host="example.com")
1020 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001021 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001022 try:
1023 while 1:
1024 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001025 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001026 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001027 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001028 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001029
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001030 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001031 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001032 from http.cookiejar import CookieJar
1033 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001034
1035 cj = CookieJar()
1036 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001037 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001038 hdeh = urllib.request.HTTPDefaultErrorHandler()
1039 hrh = urllib.request.HTTPRedirectHandler()
1040 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001041 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001042 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001043 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001044
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001045 def test_proxy(self):
1046 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001047 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001048 o.add_handler(ph)
1049 meth_spec = [
1050 [("http_open", "return response")]
1051 ]
1052 handlers = add_ordered_mock_handlers(o, meth_spec)
1053
1054 req = Request("http://acme.example.com/")
1055 self.assertEqual(req.get_host(), "acme.example.com")
1056 r = o.open(req)
1057 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1058
1059 self.assertEqual([(handlers[0], "http_open")],
1060 [tup[0:2] for tup in o.calls])
1061
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001062 def test_proxy_no_proxy(self):
1063 os.environ['no_proxy'] = 'python.org'
1064 o = OpenerDirector()
1065 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1066 o.add_handler(ph)
1067 req = Request("http://www.perl.org/")
1068 self.assertEqual(req.get_host(), "www.perl.org")
1069 r = o.open(req)
1070 self.assertEqual(req.get_host(), "proxy.example.com")
1071 req = Request("http://www.python.org")
1072 self.assertEqual(req.get_host(), "www.python.org")
1073 r = o.open(req)
1074 self.assertEqual(req.get_host(), "www.python.org")
1075 del os.environ['no_proxy']
1076
1077
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001078 def test_proxy_https(self):
1079 o = OpenerDirector()
1080 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1081 o.add_handler(ph)
1082 meth_spec = [
1083 [("https_open", "return response")]
1084 ]
1085 handlers = add_ordered_mock_handlers(o, meth_spec)
1086
1087 req = Request("https://www.example.com/")
1088 self.assertEqual(req.get_host(), "www.example.com")
1089 r = o.open(req)
1090 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1091 self.assertEqual([(handlers[0], "https_open")],
1092 [tup[0:2] for tup in o.calls])
1093
Senthil Kumaran47fff872009-12-20 07:10:31 +00001094 def test_proxy_https_proxy_authorization(self):
1095 o = OpenerDirector()
1096 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1097 o.add_handler(ph)
1098 https_handler = MockHTTPSHandler()
1099 o.add_handler(https_handler)
1100 req = Request("https://www.example.com/")
1101 req.add_header("Proxy-Authorization","FooBar")
1102 req.add_header("User-Agent","Grail")
1103 self.assertEqual(req.get_host(), "www.example.com")
1104 self.assertIsNone(req._tunnel_host)
1105 r = o.open(req)
1106 # Verify Proxy-Authorization gets tunneled to request.
1107 # httpsconn req_headers do not have the Proxy-Authorization header but
1108 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001109 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001110 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001111 self.assertIn(("User-Agent","Grail"),
1112 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001113 self.assertIsNotNone(req._tunnel_host)
1114 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1115 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001116
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001117 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001118 opener = OpenerDirector()
1119 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001120 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001121 realm = "ACME Widget Store"
1122 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001123 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1124 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001125 opener.add_handler(auth_handler)
1126 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001127 self._test_basic_auth(opener, auth_handler, "Authorization",
1128 realm, http_handler, password_manager,
1129 "http://acme.example.com/protected",
1130 "http://acme.example.com/protected",
1131 )
1132
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001133 def test_basic_auth_with_single_quoted_realm(self):
1134 self.test_basic_auth(quote_char="'")
1135
Thomas Wouters477c8d52006-05-27 19:21:47 +00001136 def test_proxy_basic_auth(self):
1137 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001138 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001139 opener.add_handler(ph)
1140 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001141 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001142 realm = "ACME Networks"
1143 http_handler = MockHTTPHandler(
1144 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001145 opener.add_handler(auth_handler)
1146 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001147 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001148 realm, http_handler, password_manager,
1149 "http://acme.example.com:3128/protected",
1150 "proxy.example.com:3128",
1151 )
1152
1153 def test_basic_and_digest_auth_handlers(self):
1154 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1155 # response (http://python.org/sf/1479302), where it should instead
1156 # return None to allow another handler (especially
1157 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001158
1159 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1160 # try digest first (since it's the strongest auth scheme), so we record
1161 # order of calls here to check digest comes first:
1162 class RecordingOpenerDirector(OpenerDirector):
1163 def __init__(self):
1164 OpenerDirector.__init__(self)
1165 self.recorded = []
1166 def record(self, info):
1167 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001168 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001169 def http_error_401(self, *args, **kwds):
1170 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001171 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001172 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001173 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001174 def http_error_401(self, *args, **kwds):
1175 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001176 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001177 *args, **kwds)
1178
1179 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001180 password_manager = MockPasswordManager()
1181 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001182 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001183 realm = "ACME Networks"
1184 http_handler = MockHTTPHandler(
1185 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001186 opener.add_handler(basic_handler)
1187 opener.add_handler(digest_handler)
1188 opener.add_handler(http_handler)
1189
1190 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001191 self._test_basic_auth(opener, basic_handler, "Authorization",
1192 realm, http_handler, password_manager,
1193 "http://acme.example.com/protected",
1194 "http://acme.example.com/protected",
1195 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001196 # check digest was tried before basic (twice, because
1197 # _test_basic_auth called .open() twice)
1198 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001199
1200 def _test_basic_auth(self, opener, auth_handler, auth_header,
1201 realm, http_handler, password_manager,
1202 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001203 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001204 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001205
1206 # .add_password() fed through to password manager
1207 auth_handler.add_password(realm, request_url, user, password)
1208 self.assertEqual(realm, password_manager.realm)
1209 self.assertEqual(request_url, password_manager.url)
1210 self.assertEqual(user, password_manager.user)
1211 self.assertEqual(password, password_manager.password)
1212
1213 r = opener.open(request_url)
1214
1215 # should have asked the password manager for the username/password
1216 self.assertEqual(password_manager.target_realm, realm)
1217 self.assertEqual(password_manager.target_url, protected_url)
1218
1219 # expect one request without authorization, then one with
1220 self.assertEqual(len(http_handler.requests), 2)
1221 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001222 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001223 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001224 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001225 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1226 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001227 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1228 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001229 # if the password manager can't find a password, the handler won't
1230 # handle the HTTP auth error
1231 password_manager.user = password_manager.password = None
1232 http_handler.reset()
1233 r = opener.open(request_url)
1234 self.assertEqual(len(http_handler.requests), 1)
1235 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1236
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001237class MiscTests(unittest.TestCase):
1238
1239 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001240 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1241 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001242 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001243 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001244 def bar_open(self): pass
1245
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001246 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001247
1248 o = build_opener(FooHandler, BarHandler)
1249 self.opener_has_handler(o, FooHandler)
1250 self.opener_has_handler(o, BarHandler)
1251
1252 # can take a mix of classes and instances
1253 o = build_opener(FooHandler, BarHandler())
1254 self.opener_has_handler(o, FooHandler)
1255 self.opener_has_handler(o, BarHandler)
1256
1257 # subclasses of default handlers override default handlers
1258 o = build_opener(MyHTTPHandler)
1259 self.opener_has_handler(o, MyHTTPHandler)
1260
1261 # a particular case of overriding: default handlers can be passed
1262 # in explicitly
1263 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001264 self.opener_has_handler(o, urllib.request.HTTPHandler)
1265 o = build_opener(urllib.request.HTTPHandler)
1266 self.opener_has_handler(o, urllib.request.HTTPHandler)
1267 o = build_opener(urllib.request.HTTPHandler())
1268 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001269
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001270 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001271 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001272 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1273 self.opener_has_handler(o, MyHTTPHandler)
1274 self.opener_has_handler(o, MyOtherHTTPHandler)
1275
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001276 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001277 self.assertTrue(any(h.__class__ == handler_class
1278 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001279
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001280class RequestTests(unittest.TestCase):
1281
1282 def setUp(self):
1283 self.get = Request("http://www.python.org/~jeremy/")
1284 self.post = Request("http://www.python.org/~jeremy/",
1285 "data",
1286 headers={"X-Test": "test"})
1287
1288 def test_method(self):
1289 self.assertEqual("POST", self.post.get_method())
1290 self.assertEqual("GET", self.get.get_method())
1291
1292 def test_add_data(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001293 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001294 self.assertEqual("GET", self.get.get_method())
1295 self.get.add_data("spam")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001296 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001297 self.assertEqual("POST", self.get.get_method())
1298
1299 def test_get_full_url(self):
1300 self.assertEqual("http://www.python.org/~jeremy/",
1301 self.get.get_full_url())
1302
1303 def test_selector(self):
1304 self.assertEqual("/~jeremy/", self.get.get_selector())
1305 req = Request("http://www.python.org/")
1306 self.assertEqual("/", req.get_selector())
1307
1308 def test_get_type(self):
1309 self.assertEqual("http", self.get.get_type())
1310
1311 def test_get_host(self):
1312 self.assertEqual("www.python.org", self.get.get_host())
1313
1314 def test_get_host_unquote(self):
1315 req = Request("http://www.%70ython.org/")
1316 self.assertEqual("www.python.org", req.get_host())
1317
1318 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001319 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001320 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001321 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001322 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1323 self.assertEqual("www.perl.org", self.get.get_host())
1324
Senthil Kumarand95cc752010-08-08 11:27:53 +00001325 def test_wrapped_url(self):
1326 req = Request("<URL:http://www.python.org>")
1327 self.assertEqual("www.python.org", req.get_host())
1328
1329 def test_urlwith_fragment(self):
1330 req = Request("http://www.python.org/?qs=query#fragment=true")
1331 self.assertEqual("/?qs=query", req.get_selector())
1332 req = Request("http://www.python.org/#fun=true")
1333 self.assertEqual("/", req.get_selector())
1334
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001335
1336def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001337 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001338 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001339 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001340 tests = (TrivialTests,
1341 OpenerDirectorTests,
1342 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001343 MiscTests,
1344 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001345 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001346
1347if __name__ == "__main__":
1348 test_main(verbose=True)