blob: b8a609e4dcd276475dd02f3ae1899336bccb868c [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
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000842 file_obj = io.StringIO()
843 file_obj.write("Something\nSomething\nSomething\n")
844
845 for headers in {}, {"Content-Length": 30}:
846 req = Request("http://example.com/", file_obj, headers)
847 if not headers:
848 # Having an iterable body without a Content-Length should
849 # raise an exception
850 self.assertRaises(ValueError, h.do_request_, req)
851 else:
852 newreq = h.do_request_(req)
853 self.assertEqual(int(newreq.get_header('Content-length')),30)
854
855 file_obj.close()
856
857 # array.array Iterable - Content Length is calculated
858
859 iterable_array = array.array("I",[1,2,3,4])
860
861 for headers in {}, {"Content-Length": 16}:
862 req = Request("http://example.com/", iterable_array, headers)
863 newreq = h.do_request_(req)
864 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000865
866
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000867 def test_http_doubleslash(self):
868 # Checks the presence of any unnecessary double slash in url does not
869 # break anything. Previously, a double slash directly after the host
870 # could could cause incorrect parsing.
871 h = urllib.request.AbstractHTTPHandler()
872 o = h.parent = MockOpener()
873
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000874 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000875 ds_urls = [
876 "http://example.com/foo/bar/baz.html",
877 "http://example.com//foo/bar/baz.html",
878 "http://example.com/foo//bar/baz.html",
879 "http://example.com/foo/bar//baz.html"
880 ]
881
882 for ds_url in ds_urls:
883 ds_req = Request(ds_url, data)
884
885 # Check whether host is determined correctly if there is no proxy
886 np_ds_req = h.do_request_(ds_req)
887 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
888
889 # Check whether host is determined correctly if there is a proxy
890 ds_req.set_proxy("someproxy:3128",None)
891 p_ds_req = h.do_request_(ds_req)
892 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
893
Senthil Kumaranc2958622010-11-22 04:48:26 +0000894 def test_fixpath_in_weirdurls(self):
895 # Issue4493: urllib2 to supply '/' when to urls where path does not
896 # start with'/'
897
898 h = urllib.request.AbstractHTTPHandler()
899 o = h.parent = MockOpener()
900
901 weird_url = 'http://www.python.org?getspam'
902 req = Request(weird_url)
903 newreq = h.do_request_(req)
904 self.assertEqual(newreq.host,'www.python.org')
905 self.assertEqual(newreq.selector,'/?getspam')
906
907 url_without_path = 'http://www.python.org'
908 req = Request(url_without_path)
909 newreq = h.do_request_(req)
910 self.assertEqual(newreq.host,'www.python.org')
911 self.assertEqual(newreq.selector,'')
912
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000913
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000914 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000915 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000916 o = h.parent = MockOpener()
917
918 url = "http://example.com/"
919 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000920 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000921 r = MockResponse(200, "OK", {}, "", url)
922 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000923 self.assertIs(r, newr)
924 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000925 r = MockResponse(202, "Accepted", {}, "", 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(206, "Partial content", {}, "", 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
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000933 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000934 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000935 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000936 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000937 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000938
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000939 def test_cookies(self):
940 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000941 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000942 o = h.parent = MockOpener()
943
944 req = Request("http://example.com/")
945 r = MockResponse(200, "OK", {}, "")
946 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000947 self.assertIs(cj.ach_req, req)
948 self.assertIs(cj.ach_req, newreq)
949 self.assertEqual(req.get_origin_req_host(), "example.com")
950 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000951 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000952 self.assertIs(cj.ec_req, req)
953 self.assertIs(cj.ec_r, r)
954 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000955
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000956 def test_redirect(self):
957 from_url = "http://example.com/a.html"
958 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000959 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000960 o = h.parent = MockOpener()
961
962 # ordinary redirect behaviour
963 for code in 301, 302, 303, 307:
964 for data in None, "blah\nblah\n":
965 method = getattr(h, "http_error_%s" % code)
966 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000967 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000968 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000969 if data is not None:
970 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000971 req.add_unredirected_header("Spam", "spam")
972 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000973 method(req, MockFile(), code, "Blah",
974 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000975 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000976 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000977 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000978 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000979 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000980 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000981 except AttributeError:
Florent Xicluna419e3842010-08-08 16:16:07 +0000982 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +0000983
984 # now it's a GET, there should not be headers regarding content
985 # (possibly dragged from before being a POST)
986 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +0000987 self.assertNotIn("content-length", headers)
988 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +0000989
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000990 self.assertEqual(o.req.headers["Nonsense"],
991 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +0000992 self.assertNotIn("Spam", o.req.headers)
993 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000994
995 # loop detection
996 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000997 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000998 def redirect(h, req, url=to_url):
999 h.http_error_302(req, MockFile(), 302, "Blah",
1000 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001001 # Note that the *original* request shares the same record of
1002 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001003
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001004 # detect infinite loop redirect of a URL to itself
1005 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001006 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001007 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001008 try:
1009 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001010 redirect(h, req, "http://example.com/")
1011 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001012 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001013 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001014 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001015
1016 # detect endless non-repeating chain of redirects
1017 req = Request(from_url, origin_req_host="example.com")
1018 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001019 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001020 try:
1021 while 1:
1022 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001023 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001024 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001025 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001026 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001027
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001028 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001029 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001030 from http.cookiejar import CookieJar
1031 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001032
1033 cj = CookieJar()
1034 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001035 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001036 hdeh = urllib.request.HTTPDefaultErrorHandler()
1037 hrh = urllib.request.HTTPRedirectHandler()
1038 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001039 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001040 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001041 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001042
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001043 def test_proxy(self):
1044 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001045 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001046 o.add_handler(ph)
1047 meth_spec = [
1048 [("http_open", "return response")]
1049 ]
1050 handlers = add_ordered_mock_handlers(o, meth_spec)
1051
1052 req = Request("http://acme.example.com/")
1053 self.assertEqual(req.get_host(), "acme.example.com")
1054 r = o.open(req)
1055 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1056
1057 self.assertEqual([(handlers[0], "http_open")],
1058 [tup[0:2] for tup in o.calls])
1059
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001060 def test_proxy_no_proxy(self):
1061 os.environ['no_proxy'] = 'python.org'
1062 o = OpenerDirector()
1063 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1064 o.add_handler(ph)
1065 req = Request("http://www.perl.org/")
1066 self.assertEqual(req.get_host(), "www.perl.org")
1067 r = o.open(req)
1068 self.assertEqual(req.get_host(), "proxy.example.com")
1069 req = Request("http://www.python.org")
1070 self.assertEqual(req.get_host(), "www.python.org")
1071 r = o.open(req)
1072 self.assertEqual(req.get_host(), "www.python.org")
1073 del os.environ['no_proxy']
1074
1075
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001076 def test_proxy_https(self):
1077 o = OpenerDirector()
1078 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1079 o.add_handler(ph)
1080 meth_spec = [
1081 [("https_open", "return response")]
1082 ]
1083 handlers = add_ordered_mock_handlers(o, meth_spec)
1084
1085 req = Request("https://www.example.com/")
1086 self.assertEqual(req.get_host(), "www.example.com")
1087 r = o.open(req)
1088 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1089 self.assertEqual([(handlers[0], "https_open")],
1090 [tup[0:2] for tup in o.calls])
1091
Senthil Kumaran47fff872009-12-20 07:10:31 +00001092 def test_proxy_https_proxy_authorization(self):
1093 o = OpenerDirector()
1094 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1095 o.add_handler(ph)
1096 https_handler = MockHTTPSHandler()
1097 o.add_handler(https_handler)
1098 req = Request("https://www.example.com/")
1099 req.add_header("Proxy-Authorization","FooBar")
1100 req.add_header("User-Agent","Grail")
1101 self.assertEqual(req.get_host(), "www.example.com")
1102 self.assertIsNone(req._tunnel_host)
1103 r = o.open(req)
1104 # Verify Proxy-Authorization gets tunneled to request.
1105 # httpsconn req_headers do not have the Proxy-Authorization header but
1106 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001107 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001108 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001109 self.assertIn(("User-Agent","Grail"),
1110 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001111 self.assertIsNotNone(req._tunnel_host)
1112 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1113 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001114
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001115 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001116 opener = OpenerDirector()
1117 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001118 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001119 realm = "ACME Widget Store"
1120 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001121 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1122 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001123 opener.add_handler(auth_handler)
1124 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001125 self._test_basic_auth(opener, auth_handler, "Authorization",
1126 realm, http_handler, password_manager,
1127 "http://acme.example.com/protected",
1128 "http://acme.example.com/protected",
1129 )
1130
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001131 def test_basic_auth_with_single_quoted_realm(self):
1132 self.test_basic_auth(quote_char="'")
1133
Thomas Wouters477c8d52006-05-27 19:21:47 +00001134 def test_proxy_basic_auth(self):
1135 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001136 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001137 opener.add_handler(ph)
1138 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001139 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001140 realm = "ACME Networks"
1141 http_handler = MockHTTPHandler(
1142 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001143 opener.add_handler(auth_handler)
1144 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001145 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001146 realm, http_handler, password_manager,
1147 "http://acme.example.com:3128/protected",
1148 "proxy.example.com:3128",
1149 )
1150
1151 def test_basic_and_digest_auth_handlers(self):
1152 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1153 # response (http://python.org/sf/1479302), where it should instead
1154 # return None to allow another handler (especially
1155 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001156
1157 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1158 # try digest first (since it's the strongest auth scheme), so we record
1159 # order of calls here to check digest comes first:
1160 class RecordingOpenerDirector(OpenerDirector):
1161 def __init__(self):
1162 OpenerDirector.__init__(self)
1163 self.recorded = []
1164 def record(self, info):
1165 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001166 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001167 def http_error_401(self, *args, **kwds):
1168 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001169 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001170 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001171 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001172 def http_error_401(self, *args, **kwds):
1173 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001174 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001175 *args, **kwds)
1176
1177 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001178 password_manager = MockPasswordManager()
1179 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001180 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001181 realm = "ACME Networks"
1182 http_handler = MockHTTPHandler(
1183 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001184 opener.add_handler(basic_handler)
1185 opener.add_handler(digest_handler)
1186 opener.add_handler(http_handler)
1187
1188 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001189 self._test_basic_auth(opener, basic_handler, "Authorization",
1190 realm, http_handler, password_manager,
1191 "http://acme.example.com/protected",
1192 "http://acme.example.com/protected",
1193 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001194 # check digest was tried before basic (twice, because
1195 # _test_basic_auth called .open() twice)
1196 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001197
1198 def _test_basic_auth(self, opener, auth_handler, auth_header,
1199 realm, http_handler, password_manager,
1200 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001201 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001202 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001203
1204 # .add_password() fed through to password manager
1205 auth_handler.add_password(realm, request_url, user, password)
1206 self.assertEqual(realm, password_manager.realm)
1207 self.assertEqual(request_url, password_manager.url)
1208 self.assertEqual(user, password_manager.user)
1209 self.assertEqual(password, password_manager.password)
1210
1211 r = opener.open(request_url)
1212
1213 # should have asked the password manager for the username/password
1214 self.assertEqual(password_manager.target_realm, realm)
1215 self.assertEqual(password_manager.target_url, protected_url)
1216
1217 # expect one request without authorization, then one with
1218 self.assertEqual(len(http_handler.requests), 2)
1219 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001220 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001221 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001222 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001223 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1224 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001225 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1226 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001227 # if the password manager can't find a password, the handler won't
1228 # handle the HTTP auth error
1229 password_manager.user = password_manager.password = None
1230 http_handler.reset()
1231 r = opener.open(request_url)
1232 self.assertEqual(len(http_handler.requests), 1)
1233 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1234
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001235class MiscTests(unittest.TestCase):
1236
1237 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001238 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1239 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001240 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001241 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001242 def bar_open(self): pass
1243
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001244 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001245
1246 o = build_opener(FooHandler, BarHandler)
1247 self.opener_has_handler(o, FooHandler)
1248 self.opener_has_handler(o, BarHandler)
1249
1250 # can take a mix of classes and instances
1251 o = build_opener(FooHandler, BarHandler())
1252 self.opener_has_handler(o, FooHandler)
1253 self.opener_has_handler(o, BarHandler)
1254
1255 # subclasses of default handlers override default handlers
1256 o = build_opener(MyHTTPHandler)
1257 self.opener_has_handler(o, MyHTTPHandler)
1258
1259 # a particular case of overriding: default handlers can be passed
1260 # in explicitly
1261 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001262 self.opener_has_handler(o, urllib.request.HTTPHandler)
1263 o = build_opener(urllib.request.HTTPHandler)
1264 self.opener_has_handler(o, urllib.request.HTTPHandler)
1265 o = build_opener(urllib.request.HTTPHandler())
1266 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001267
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001268 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001269 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001270 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1271 self.opener_has_handler(o, MyHTTPHandler)
1272 self.opener_has_handler(o, MyOtherHTTPHandler)
1273
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001274 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001275 self.assertTrue(any(h.__class__ == handler_class
1276 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001277
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001278class RequestTests(unittest.TestCase):
1279
1280 def setUp(self):
1281 self.get = Request("http://www.python.org/~jeremy/")
1282 self.post = Request("http://www.python.org/~jeremy/",
1283 "data",
1284 headers={"X-Test": "test"})
1285
1286 def test_method(self):
1287 self.assertEqual("POST", self.post.get_method())
1288 self.assertEqual("GET", self.get.get_method())
1289
1290 def test_add_data(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001291 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001292 self.assertEqual("GET", self.get.get_method())
1293 self.get.add_data("spam")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001294 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001295 self.assertEqual("POST", self.get.get_method())
1296
1297 def test_get_full_url(self):
1298 self.assertEqual("http://www.python.org/~jeremy/",
1299 self.get.get_full_url())
1300
1301 def test_selector(self):
1302 self.assertEqual("/~jeremy/", self.get.get_selector())
1303 req = Request("http://www.python.org/")
1304 self.assertEqual("/", req.get_selector())
1305
1306 def test_get_type(self):
1307 self.assertEqual("http", self.get.get_type())
1308
1309 def test_get_host(self):
1310 self.assertEqual("www.python.org", self.get.get_host())
1311
1312 def test_get_host_unquote(self):
1313 req = Request("http://www.%70ython.org/")
1314 self.assertEqual("www.python.org", req.get_host())
1315
1316 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001317 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001318 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001319 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001320 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1321 self.assertEqual("www.perl.org", self.get.get_host())
1322
Senthil Kumarand95cc752010-08-08 11:27:53 +00001323 def test_wrapped_url(self):
1324 req = Request("<URL:http://www.python.org>")
1325 self.assertEqual("www.python.org", req.get_host())
1326
1327 def test_urlwith_fragment(self):
1328 req = Request("http://www.python.org/?qs=query#fragment=true")
1329 self.assertEqual("/?qs=query", req.get_selector())
1330 req = Request("http://www.python.org/#fun=true")
1331 self.assertEqual("/", req.get_selector())
1332
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001333
1334def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001335 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001336 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001337 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001338 tests = (TrivialTests,
1339 OpenerDirectorTests,
1340 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001341 MiscTests,
1342 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001343 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001344
1345if __name__ == "__main__":
1346 test_main(verbose=True)