blob: 1704683b4dd61ac357ccb6ba98ccb90d80389584 [file] [log] [blame]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002from test import support
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00003
Christian Heimes05e8be12008-02-23 18:30:17 +00004import os
Guido van Rossum34d19282007-08-09 01:03:29 +00005import io
Georg Brandlf78e02b2008-06-10 17:40:04 +00006import socket
Jeremy Hyltone3e61042001-05-09 15:50:25 +00007
Jeremy Hylton1afc1692008-06-18 20:49:58 +00008import urllib.request
Ronald Oussorene72e1612011-03-14 18:15:25 -04009# The proxy bypass method imported below has logic specific to the OSX
10# proxy config data structure but is testable on all platforms.
11from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
Jeremy Hyltone3e61042001-05-09 15:50:25 +000012
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000013# XXX
14# Request
15# CacheFTPHandler (hard to write)
Thomas Wouters477c8d52006-05-27 19:21:47 +000016# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000017
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000018class TrivialTests(unittest.TestCase):
19 def test_trivial(self):
20 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000021
Jeremy Hylton1afc1692008-06-18 20:49:58 +000022 self.assertRaises(ValueError, urllib.request.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000023
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000024 # XXX Name hacking to get this to work on Windows.
Jeremy Hylton1afc1692008-06-18 20:49:58 +000025 fname = os.path.abspath(urllib.request.__file__).replace('\\', '/')
Senthil Kumaran673d7e92010-01-10 17:48:37 +000026
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000027 # And more hacking to get it to work on MacOS. This assumes
28 # urllib.pathname2url works, unfortunately...
29 if os.name == 'mac':
30 fname = '/' + fname.replace(':', '/')
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000031
Senthil Kumaran673d7e92010-01-10 17:48:37 +000032 if os.name == 'nt':
33 file_url = "file:///%s" % fname
34 else:
35 file_url = "file://%s" % fname
36
Jeremy Hylton1afc1692008-06-18 20:49:58 +000037 f = urllib.request.urlopen(file_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000038
39 buf = f.read()
40 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000041
Georg Brandle1b13d22005-08-24 22:20:32 +000042 def test_parse_http_list(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000043 tests = [
44 ('a,b,c', ['a', 'b', 'c']),
45 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
46 ('a, b, "c", "d", "e,f", g, h',
47 ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
48 ('a="b\\"c", d="e\\,f", g="h\\\\i"',
49 ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
Georg Brandle1b13d22005-08-24 22:20:32 +000050 for string, list in tests:
Florent Xiclunab4efb3d2010-08-14 18:24:40 +000051 self.assertEqual(urllib.request.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000052
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000053
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000054def test_request_headers_dict():
55 """
56 The Request.headers dictionary is not a documented interface. It should
57 stay that way, because the complete set of headers are only accessible
58 through the .get_header(), .has_header(), .header_items() interface.
59 However, .headers pre-dates those methods, and so real code will be using
60 the dictionary.
61
62 The introduction in 2.4 of those methods was a mistake for the same reason:
63 code that previously saw all (urllib2 user)-provided headers in .headers
64 now sees only a subset (and the function interface is ugly and incomplete).
65 A better change would have been to replace .headers dict with a dict
66 subclass (or UserDict.DictMixin instance?) that preserved the .headers
67 interface and also provided access to the "unredirected" headers. It's
68 probably too late to fix that, though.
69
70
71 Check .capitalize() case normalization:
72
73 >>> url = "http://example.com"
74 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
75 'blah'
76 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
77 'blah'
78
79 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
80 but that could be changed in future.
81
82 """
83
84def test_request_headers_methods():
85 """
86 Note the case normalization of header names here, to .capitalize()-case.
87 This should be preserved for backwards-compatibility. (In the HTTP case,
88 normalization to .title()-case is done by urllib2 before sending headers to
Georg Brandl24420152008-05-26 16:32:26 +000089 http.client).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000090
91 >>> url = "http://example.com"
92 >>> r = Request(url, headers={"Spam-eggs": "blah"})
93 >>> r.has_header("Spam-eggs")
94 True
95 >>> r.header_items()
96 [('Spam-eggs', 'blah')]
97 >>> r.add_header("Foo-Bar", "baz")
Guido van Rossumcc2b0162007-02-11 06:12:03 +000098 >>> items = sorted(r.header_items())
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000099 >>> items
100 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
101
102 Note that e.g. r.has_header("spam-EggS") is currently False, and
103 r.get_header("spam-EggS") returns None, but that could be changed in
104 future.
105
106 >>> r.has_header("Not-there")
107 False
Guido van Rossum7131f842007-02-09 20:13:25 +0000108 >>> print(r.get_header("Not-there"))
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000109 None
110 >>> r.get_header("Not-there", "default")
111 'default'
112
113 """
114
115
Thomas Wouters477c8d52006-05-27 19:21:47 +0000116def test_password_manager(self):
117 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000118 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000119 >>> add = mgr.add_password
120 >>> add("Some Realm", "http://example.com/", "joe", "password")
121 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
122 >>> add("c", "http://example.com/foo", "foo", "ni")
123 >>> add("c", "http://example.com/bar", "bar", "nini")
124 >>> add("b", "http://example.com/", "first", "blah")
125 >>> add("b", "http://example.com/", "second", "spam")
126 >>> add("a", "http://example.com", "1", "a")
127 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
128 >>> add("Some Realm", "d.example.com", "4", "d")
129 >>> add("Some Realm", "e.example.com:3128", "5", "e")
130
131 >>> mgr.find_user_password("Some Realm", "example.com")
132 ('joe', 'password')
133 >>> mgr.find_user_password("Some Realm", "http://example.com")
134 ('joe', 'password')
135 >>> mgr.find_user_password("Some Realm", "http://example.com/")
136 ('joe', 'password')
137 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
138 ('joe', 'password')
139 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
140 ('joe', 'password')
141 >>> mgr.find_user_password("c", "http://example.com/foo")
142 ('foo', 'ni')
143 >>> mgr.find_user_password("c", "http://example.com/bar")
144 ('bar', 'nini')
145
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000146 Actually, this is really undefined ATM
147## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000148
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000149## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
150## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000151
152 Use latest add_password() in case of conflict:
153
154 >>> mgr.find_user_password("b", "http://example.com/")
155 ('second', 'spam')
156
157 No special relationship between a.example.com and example.com:
158
159 >>> mgr.find_user_password("a", "http://example.com/")
160 ('1', 'a')
161 >>> mgr.find_user_password("a", "http://a.example.com/")
162 (None, None)
163
164 Ports:
165
166 >>> mgr.find_user_password("Some Realm", "c.example.com")
167 (None, None)
168 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
169 ('3', 'c')
170 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
171 ('3', 'c')
172 >>> mgr.find_user_password("Some Realm", "d.example.com")
173 ('4', 'd')
174 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
175 ('5', 'e')
176
177 """
178 pass
179
180
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000181def test_password_manager_default_port(self):
182 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000183 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000184 >>> add = mgr.add_password
185
186 The point to note here is that we can't guess the default port if there's
187 no scheme. This applies to both add_password and find_user_password.
188
189 >>> add("f", "http://g.example.com:80", "10", "j")
190 >>> add("g", "http://h.example.com", "11", "k")
191 >>> add("h", "i.example.com:80", "12", "l")
192 >>> add("i", "j.example.com", "13", "m")
193 >>> mgr.find_user_password("f", "g.example.com:100")
194 (None, None)
195 >>> mgr.find_user_password("f", "g.example.com:80")
196 ('10', 'j')
197 >>> mgr.find_user_password("f", "g.example.com")
198 (None, None)
199 >>> mgr.find_user_password("f", "http://g.example.com:100")
200 (None, None)
201 >>> mgr.find_user_password("f", "http://g.example.com:80")
202 ('10', 'j')
203 >>> mgr.find_user_password("f", "http://g.example.com")
204 ('10', 'j')
205 >>> mgr.find_user_password("g", "h.example.com")
206 ('11', 'k')
207 >>> mgr.find_user_password("g", "h.example.com:80")
208 ('11', 'k')
209 >>> mgr.find_user_password("g", "http://h.example.com:80")
210 ('11', 'k')
211 >>> mgr.find_user_password("h", "i.example.com")
212 (None, None)
213 >>> mgr.find_user_password("h", "i.example.com:80")
214 ('12', 'l')
215 >>> mgr.find_user_password("h", "http://i.example.com:80")
216 ('12', 'l')
217 >>> mgr.find_user_password("i", "j.example.com")
218 ('13', 'm')
219 >>> mgr.find_user_password("i", "j.example.com:80")
220 (None, None)
221 >>> mgr.find_user_password("i", "http://j.example.com")
222 ('13', 'm')
223 >>> mgr.find_user_password("i", "http://j.example.com:80")
224 (None, None)
225
226 """
227
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000228class MockOpener:
229 addheaders = []
Senthil Kumarane9da06f2009-07-19 04:20:12 +0000230 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
231 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000232 def error(self, proto, *args):
233 self.proto, self.args = proto, args
234
235class MockFile:
236 def read(self, count=None): pass
237 def readline(self, count=None): pass
238 def close(self): pass
239
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000240class MockHeaders(dict):
241 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000242 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000243
Guido van Rossum34d19282007-08-09 01:03:29 +0000244class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000245 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000246 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000247 self.code, self.msg, self.headers, self.url = code, msg, headers, url
248 def info(self):
249 return self.headers
250 def geturl(self):
251 return self.url
252
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000253class MockCookieJar:
254 def add_cookie_header(self, request):
255 self.ach_req = request
256 def extract_cookies(self, response, request):
257 self.ec_req, self.ec_r = request, response
258
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000259class FakeMethod:
260 def __init__(self, meth_name, action, handle):
261 self.meth_name = meth_name
262 self.handle = handle
263 self.action = action
264 def __call__(self, *args):
265 return self.handle(self.meth_name, self.action, *args)
266
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +0000267class MockHTTPResponse(io.IOBase):
268 def __init__(self, fp, msg, status, reason):
269 self.fp = fp
270 self.msg = msg
271 self.status = status
272 self.reason = reason
273 self.code = 200
274
275 def read(self):
276 return ''
277
278 def info(self):
279 return {}
280
281 def geturl(self):
282 return self.url
283
284
285class MockHTTPClass:
286 def __init__(self):
287 self.level = 0
288 self.req_headers = []
289 self.data = None
290 self.raise_on_endheaders = False
291 self._tunnel_headers = {}
292
293 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
294 self.host = host
295 self.timeout = timeout
296 return self
297
298 def set_debuglevel(self, level):
299 self.level = level
300
301 def _set_tunnel(self, host, port=None, headers=None):
302 self._tunnel_host = host
303 self._tunnel_port = port
304 if headers:
305 self._tunnel_headers = headers
306 else:
307 self._tunnel_headers.clear()
308
Benjamin Peterson794921a2009-12-24 01:18:13 +0000309 def request(self, method, url, body=None, headers=None):
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +0000310 self.method = method
311 self.selector = url
Benjamin Peterson794921a2009-12-24 01:18:13 +0000312 if headers is not None:
313 self.req_headers += headers.items()
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +0000314 self.req_headers.sort()
315 if body:
316 self.data = body
317 if self.raise_on_endheaders:
318 import socket
319 raise socket.error()
320 def getresponse(self):
321 return MockHTTPResponse(MockFile(), {}, 200, "OK")
322
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000323class MockHandler:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000324 # useful for testing handler machinery
325 # see add_ordered_mock_handlers() docstring
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000326 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000327 def __init__(self, methods):
328 self._define_methods(methods)
329 def _define_methods(self, methods):
330 for spec in methods:
331 if len(spec) == 2: name, action = spec
332 else: name, action = spec, None
333 meth = FakeMethod(name, action, self.handle)
334 setattr(self.__class__, name, meth)
335 def handle(self, fn_name, action, *args, **kwds):
336 self.parent.calls.append((self, fn_name, args, kwds))
337 if action is None:
338 return None
339 elif action == "return self":
340 return self
341 elif action == "return response":
342 res = MockResponse(200, "OK", {}, "")
343 return res
344 elif action == "return request":
345 return Request("http://blah/")
346 elif action.startswith("error"):
347 code = action[action.rfind(" ")+1:]
348 try:
349 code = int(code)
350 except ValueError:
351 pass
352 res = MockResponse(200, "OK", {}, "")
353 return self.parent.error("http", args[0], res, code, "", {})
354 elif action == "raise":
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000355 raise urllib.error.URLError("blah")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000356 assert False
357 def close(self): pass
358 def add_parent(self, parent):
359 self.parent = parent
360 self.parent.calls = []
361 def __lt__(self, other):
362 if not hasattr(other, "handler_order"):
363 # No handler_order, leave in original order. Yuck.
364 return True
365 return self.handler_order < other.handler_order
366
367def add_ordered_mock_handlers(opener, meth_spec):
368 """Create MockHandlers and add them to an OpenerDirector.
369
370 meth_spec: list of lists of tuples and strings defining methods to define
371 on handlers. eg:
372
373 [["http_error", "ftp_open"], ["http_open"]]
374
375 defines methods .http_error() and .ftp_open() on one handler, and
376 .http_open() on another. These methods just record their arguments and
377 return None. Using a tuple instead of a string causes the method to
378 perform some action (see MockHandler.handle()), eg:
379
380 [["http_error"], [("http_open", "return request")]]
381
382 defines .http_error() on one handler (which simply returns None), and
383 .http_open() on another handler, which returns a Request object.
384
385 """
386 handlers = []
387 count = 0
388 for meths in meth_spec:
389 class MockHandlerSubclass(MockHandler): pass
390 h = MockHandlerSubclass(meths)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000391 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000392 h.add_parent(opener)
393 count = count + 1
394 handlers.append(h)
395 opener.add_handler(h)
396 return handlers
397
Thomas Wouters477c8d52006-05-27 19:21:47 +0000398def build_test_opener(*handler_instances):
399 opener = OpenerDirector()
400 for h in handler_instances:
401 opener.add_handler(h)
402 return opener
403
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000404class MockHTTPHandler(urllib.request.BaseHandler):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000405 # useful for testing redirections and auth
406 # sends supplied headers and code as first response
407 # sends 200 OK as second response
408 def __init__(self, code, headers):
409 self.code = code
410 self.headers = headers
411 self.reset()
412 def reset(self):
413 self._count = 0
414 self.requests = []
415 def http_open(self, req):
Barry Warsaw820c1202008-06-12 04:06:45 +0000416 import email, http.client, copy
Guido van Rossum34d19282007-08-09 01:03:29 +0000417 from io import StringIO
Thomas Wouters477c8d52006-05-27 19:21:47 +0000418 self.requests.append(copy.deepcopy(req))
419 if self._count == 0:
420 self._count = self._count + 1
Georg Brandl24420152008-05-26 16:32:26 +0000421 name = http.client.responses[self.code]
Barry Warsaw820c1202008-06-12 04:06:45 +0000422 msg = email.message_from_string(self.headers)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000423 return self.parent.error(
424 "http", req, MockFile(), self.code, name, msg)
425 else:
426 self.req = req
Barry Warsaw820c1202008-06-12 04:06:45 +0000427 msg = email.message_from_string("\r\n\r\n")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000428 return MockResponse(200, "OK", msg, "", req.get_full_url())
429
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +0000430class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
431 # Useful for testing the Proxy-Authorization request by verifying the
432 # properties of httpcon
Benjamin Peterson794921a2009-12-24 01:18:13 +0000433
434 def __init__(self):
435 urllib.request.AbstractHTTPHandler.__init__(self)
436 self.httpconn = MockHTTPClass()
437
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +0000438 def https_open(self, req):
439 return self.do_open(self.httpconn, req)
440
Thomas Wouters477c8d52006-05-27 19:21:47 +0000441class MockPasswordManager:
442 def add_password(self, realm, uri, user, password):
443 self.realm = realm
444 self.url = uri
445 self.user = user
446 self.password = password
447 def find_user_password(self, realm, authuri):
448 self.target_realm = realm
449 self.target_url = authuri
450 return self.user, self.password
451
452
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000453class OpenerDirectorTests(unittest.TestCase):
454
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000455 def test_add_non_handler(self):
456 class NonHandler(object):
457 pass
458 self.assertRaises(TypeError,
459 OpenerDirector().add_handler, NonHandler())
460
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000461 def test_badly_named_methods(self):
462 # test work-around for three methods that accidentally follow the
463 # naming conventions for handler methods
464 # (*_open() / *_request() / *_response())
465
466 # These used to call the accidentally-named methods, causing a
467 # TypeError in real code; here, returning self from these mock
468 # methods would either cause no exception, or AttributeError.
469
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000470 from urllib.error import URLError
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000471
472 o = OpenerDirector()
473 meth_spec = [
474 [("do_open", "return self"), ("proxy_open", "return self")],
475 [("redirect_request", "return self")],
476 ]
477 handlers = add_ordered_mock_handlers(o, meth_spec)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000478 o.add_handler(urllib.request.UnknownHandler())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000479 for scheme in "do", "proxy", "redirect":
480 self.assertRaises(URLError, o.open, scheme+"://example.com/")
481
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000482 def test_handled(self):
483 # handler returning non-None means no more handlers will be called
484 o = OpenerDirector()
485 meth_spec = [
486 ["http_open", "ftp_open", "http_error_302"],
487 ["ftp_open"],
488 [("http_open", "return self")],
489 [("http_open", "return self")],
490 ]
491 handlers = add_ordered_mock_handlers(o, meth_spec)
492
493 req = Request("http://example.com/")
494 r = o.open(req)
495 # Second .http_open() gets called, third doesn't, since second returned
496 # non-None. Handlers without .http_open() never get any methods called
497 # on them.
498 # In fact, second mock handler defining .http_open() returns self
499 # (instead of response), which becomes the OpenerDirector's return
500 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000501 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000502 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
503 for expected, got in zip(calls, o.calls):
504 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000505 self.assertEqual((handler, name), expected)
506 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000507
508 def test_handler_order(self):
509 o = OpenerDirector()
510 handlers = []
511 for meths, handler_order in [
512 ([("http_open", "return self")], 500),
513 (["http_open"], 0),
514 ]:
515 class MockHandlerSubclass(MockHandler): pass
516 h = MockHandlerSubclass(meths)
517 h.handler_order = handler_order
518 handlers.append(h)
519 o.add_handler(h)
520
521 r = o.open("http://example.com/")
522 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000523 self.assertEqual(o.calls[0][0], handlers[1])
524 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000525
526 def test_raise(self):
527 # raising URLError stops processing of request
528 o = OpenerDirector()
529 meth_spec = [
530 [("http_open", "raise")],
531 [("http_open", "return self")],
532 ]
533 handlers = add_ordered_mock_handlers(o, meth_spec)
534
535 req = Request("http://example.com/")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000536 self.assertRaises(urllib.error.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000537 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000538
539## def test_error(self):
540## # XXX this doesn't actually seem to be used in standard library,
541## # but should really be tested anyway...
542
543 def test_http_error(self):
544 # XXX http_error_default
545 # http errors are a special case
546 o = OpenerDirector()
547 meth_spec = [
548 [("http_open", "error 302")],
549 [("http_error_400", "raise"), "http_open"],
550 [("http_error_302", "return response"), "http_error_303",
551 "http_error"],
552 [("http_error_302")],
553 ]
554 handlers = add_ordered_mock_handlers(o, meth_spec)
555
556 class Unknown:
557 def __eq__(self, other): return True
558
559 req = Request("http://example.com/")
560 r = o.open(req)
561 assert len(o.calls) == 2
562 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000563 (handlers[2], "http_error_302",
564 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000565 for expected, got in zip(calls, o.calls):
566 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000567 self.assertEqual((handler, method_name), got[:2])
568 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000569
570 def test_processors(self):
571 # *_request / *_response methods get called appropriately
572 o = OpenerDirector()
573 meth_spec = [
574 [("http_request", "return request"),
575 ("http_response", "return response")],
576 [("http_request", "return request"),
577 ("http_response", "return response")],
578 ]
579 handlers = add_ordered_mock_handlers(o, meth_spec)
580
581 req = Request("http://example.com/")
582 r = o.open(req)
583 # processor methods are called on *all* handlers that define them,
584 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000585 calls = [
586 (handlers[0], "http_request"), (handlers[1], "http_request"),
587 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000588
589 for i, (handler, name, args, kwds) in enumerate(o.calls):
590 if i < 2:
591 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000592 self.assertEqual((handler, name), calls[i])
593 self.assertEqual(len(args), 1)
Georg Brandlab91fde2009-08-13 08:51:18 +0000594 self.assertTrue(isinstance(args[0], Request))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000595 else:
596 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000597 self.assertEqual((handler, name), calls[i])
598 self.assertEqual(len(args), 2)
Georg Brandlab91fde2009-08-13 08:51:18 +0000599 self.assertTrue(isinstance(args[0], Request))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000600 # response from opener.open is None, because there's no
601 # handler that defines http_open to handle it
Georg Brandlab91fde2009-08-13 08:51:18 +0000602 self.assertTrue(args[1] is None or
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000603 isinstance(args[1], MockResponse))
604
605
Tim Peters58eb11c2004-01-18 20:29:55 +0000606def sanepathname2url(path):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000607 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000608 if os.name == "nt" and urlpath.startswith("///"):
609 urlpath = urlpath[2:]
610 # XXX don't ask me about the mac...
611 return urlpath
612
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000613class HandlerTests(unittest.TestCase):
614
615 def test_ftp(self):
616 class MockFTPWrapper:
617 def __init__(self, data): self.data = data
618 def retrfile(self, filename, filetype):
619 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000620 return io.StringIO(self.data), len(self.data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000621
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000622 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000623 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000624 def connect_ftp(self, user, passwd, host, port, dirs,
625 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000626 self.user, self.passwd = user, passwd
627 self.host, self.port = host, port
628 self.dirs = dirs
629 self.ftpwrapper = MockFTPWrapper(self.data)
630 return self.ftpwrapper
631
Georg Brandlf78e02b2008-06-10 17:40:04 +0000632 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000633 data = "rheum rhaponicum"
634 h = NullFTPHandler(data)
635 o = h.parent = MockOpener()
636
Senthil Kumaran723a7a62010-11-18 16:44:38 +0000637 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000638 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumaran723a7a62010-11-18 16:44:38 +0000639 "localhost", ftplib.FTP_PORT, "", "", "I",
640 ["foo", "bar"], "baz.html", "text/html"),
641 ("ftp://parrot@localhost/foo/bar/baz.html",
642 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
643 ["foo", "bar"], "baz.html", "text/html"),
644 ("ftp://%25parrot@localhost/foo/bar/baz.html",
645 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
646 ["foo", "bar"], "baz.html", "text/html"),
647 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
648 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000649 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000650 ("ftp://localhost:80/foo/bar/",
Senthil Kumaran723a7a62010-11-18 16:44:38 +0000651 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000652 ["foo", "bar"], "", None),
653 ("ftp://localhost/baz.gif;type=a",
Senthil Kumaran723a7a62010-11-18 16:44:38 +0000654 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000655 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000656 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000657 req = Request(url)
658 req.timeout = None
659 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000660 # ftp authentication not yet implemented by FTPHandler
Senthil Kumaran723a7a62010-11-18 16:44:38 +0000661 self.assertEqual(h.user, user)
662 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000663 self.assertEqual(h.host, socket.gethostbyname(host))
664 self.assertEqual(h.port, port)
665 self.assertEqual(h.dirs, dirs)
666 self.assertEqual(h.ftpwrapper.filename, filename)
667 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000668 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000669 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000670 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000671
672 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000673 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000674 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000675 o = h.parent = MockOpener()
676
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000677 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000678 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000679 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000680 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000681 "file://localhost%s" % urlpath,
682 "file://%s" % urlpath,
683 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000684 ]
685 try:
686 localaddr = socket.gethostbyname(socket.gethostname())
687 except socket.gaierror:
688 localaddr = ''
689 if localaddr:
690 urls.append("file://%s%s" % (localaddr, urlpath))
691
692 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000693 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000694 try:
695 try:
696 f.write(towrite)
697 finally:
698 f.close()
699
700 r = h.file_open(Request(url))
701 try:
702 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000703 headers = r.info()
Senthil Kumaran51964772010-05-08 03:31:56 +0000704 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000705 finally:
706 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000707 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000708 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000709 finally:
710 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000711 self.assertEqual(data, towrite)
712 self.assertEqual(headers["Content-type"], "text/plain")
713 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000714 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran51964772010-05-08 03:31:56 +0000715 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000716
717 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000718 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000719 "file:///file_does_not_exist.txt",
720 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
721 os.getcwd(), TESTFN),
722 "file://somerandomhost.ontheinternet.com%s/%s" %
723 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000724 ]:
725 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000726 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000727 try:
728 f.write(towrite)
729 finally:
730 f.close()
731
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000732 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000733 h.file_open, Request(url))
734 finally:
735 os.remove(TESTFN)
736
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000737 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000738 o = h.parent = MockOpener()
739 # XXXX why does // mean ftp (and /// mean not ftp!), and where
740 # is file: scheme specified? I think this is really a bug, and
741 # what was intended was to distinguish between URLs like:
742 # file:/blah.txt (a file)
743 # file://localhost/blah.txt (a file)
744 # file:///blah.txt (a file)
745 # file://ftp.example.com/blah.txt (an ftp URL)
746 for url, ftp in [
747 ("file://ftp.example.com//foo.txt", True),
748 ("file://ftp.example.com///foo.txt", False),
749# XXXX bug: fails with OSError, should be URLError
750 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran34024142010-07-11 03:15:25 +0000751 ("file://somehost//foo/something.txt", True),
752 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000753 ]:
754 req = Request(url)
755 try:
756 h.file_open(req)
757 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000758 except (urllib.error.URLError, OSError):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000759 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000760 else:
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000761 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000762 self.assertEqual(req.type, "ftp")
Benjamin Petersonecb6e812011-01-12 19:29:51 +0000763 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000764
765 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000766
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000767 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000768 o = h.parent = MockOpener()
769
770 url = "http://example.com/"
771 for method, data in [("GET", None), ("POST", "blah")]:
772 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000773 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000774 req.add_unredirected_header("Spam", "eggs")
775 http = MockHTTPClass()
776 r = h.do_open(http, req)
777
778 # result attributes
779 r.read; r.readline # wrapped MockFile methods
780 r.info; r.geturl # addinfourl methods
781 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
782 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000783 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000784 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000785
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000786 self.assertEqual(http.host, "example.com")
787 self.assertEqual(http.level, 0)
788 self.assertEqual(http.method, method)
789 self.assertEqual(http.selector, "/")
790 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000791 [("Connection", "close"),
792 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000793 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000794
795 # check socket.error converted to URLError
796 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000797 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000798
799 # check adding of standard headers
800 o.addheaders = [("Spam", "eggs")]
801 for data in "", None: # POST, GET
802 req = Request("http://example.com/", data)
803 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000804 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000805 if data is None: # GET
Georg Brandlab91fde2009-08-13 08:51:18 +0000806 self.assertTrue("Content-length" not in req.unredirected_hdrs)
807 self.assertTrue("Content-type" not in req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000808 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000809 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
810 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000811 "application/x-www-form-urlencoded")
812 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000813 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
814 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000815
816 # don't clobber existing headers
817 req.add_unredirected_header("Content-length", "foo")
818 req.add_unredirected_header("Content-type", "bar")
819 req.add_unredirected_header("Host", "baz")
820 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000821 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000822 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
823 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000824 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
825 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000826
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000827 def test_http_doubleslash(self):
828 # Checks the presence of any unnecessary double slash in url does not
829 # break anything. Previously, a double slash directly after the host
830 # could could cause incorrect parsing.
831 h = urllib.request.AbstractHTTPHandler()
832 o = h.parent = MockOpener()
833
834 data = ""
835 ds_urls = [
836 "http://example.com/foo/bar/baz.html",
837 "http://example.com//foo/bar/baz.html",
838 "http://example.com/foo//bar/baz.html",
839 "http://example.com/foo/bar//baz.html"
840 ]
841
842 for ds_url in ds_urls:
843 ds_req = Request(ds_url, data)
844
845 # Check whether host is determined correctly if there is no proxy
846 np_ds_req = h.do_request_(ds_req)
847 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
848
849 # Check whether host is determined correctly if there is a proxy
850 ds_req.set_proxy("someproxy:3128",None)
851 p_ds_req = h.do_request_(ds_req)
852 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
853
Senthil Kumarand17ebdb2010-11-22 04:53:57 +0000854 def test_fixpath_in_weirdurls(self):
855 # Issue4493: urllib2 to supply '/' when to urls where path does not
856 # start with'/'
857
858 h = urllib.request.AbstractHTTPHandler()
859 o = h.parent = MockOpener()
860
861 weird_url = 'http://www.python.org?getspam'
862 req = Request(weird_url)
863 newreq = h.do_request_(req)
864 self.assertEqual(newreq.host,'www.python.org')
865 self.assertEqual(newreq.selector,'/?getspam')
866
867 url_without_path = 'http://www.python.org'
868 req = Request(url_without_path)
869 newreq = h.do_request_(req)
870 self.assertEqual(newreq.host,'www.python.org')
871 self.assertEqual(newreq.selector,'')
872
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000873
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000874 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000875 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000876 o = h.parent = MockOpener()
877
878 url = "http://example.com/"
879 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000880 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000881 r = MockResponse(200, "OK", {}, "", url)
882 newr = h.http_response(req, r)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000883 self.assertIs(r, newr)
884 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000885 r = MockResponse(202, "Accepted", {}, "", url)
886 newr = h.http_response(req, r)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000887 self.assertIs(r, newr)
888 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000889 r = MockResponse(206, "Partial content", {}, "", url)
890 newr = h.http_response(req, r)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000891 self.assertIs(r, newr)
892 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000893 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000894 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000895 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000896 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000897 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000898
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000899 def test_cookies(self):
900 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000901 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000902 o = h.parent = MockOpener()
903
904 req = Request("http://example.com/")
905 r = MockResponse(200, "OK", {}, "")
906 newreq = h.http_request(req)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000907 self.assertIs(cj.ach_req, req)
908 self.assertIs(cj.ach_req, newreq)
909 self.assertEqual(req.get_origin_req_host(), "example.com")
910 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000911 newr = h.http_response(req, r)
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000912 self.assertIs(cj.ec_req, req)
913 self.assertIs(cj.ec_r, r)
914 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000915
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000916 def test_redirect(self):
917 from_url = "http://example.com/a.html"
918 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000919 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000920 o = h.parent = MockOpener()
921
922 # ordinary redirect behaviour
923 for code in 301, 302, 303, 307:
924 for data in None, "blah\nblah\n":
925 method = getattr(h, "http_error_%s" % code)
926 req = Request(from_url, data)
Senthil Kumarane9da06f2009-07-19 04:20:12 +0000927 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000928 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000929 if data is not None:
930 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000931 req.add_unredirected_header("Spam", "spam")
932 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000933 method(req, MockFile(), code, "Blah",
934 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000935 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000936 # 307 in response to POST requires user OK
Georg Brandlab91fde2009-08-13 08:51:18 +0000937 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000938 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000939 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000940 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000941 except AttributeError:
Florent Xiclunab4efb3d2010-08-14 18:24:40 +0000942 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +0000943
944 # now it's a GET, there should not be headers regarding content
945 # (possibly dragged from before being a POST)
946 headers = [x.lower() for x in o.req.headers]
947 self.assertTrue("content-length" not in headers)
948 self.assertTrue("content-type" not in headers)
949
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000950 self.assertEqual(o.req.headers["Nonsense"],
951 "viking=withhold")
Georg Brandlab91fde2009-08-13 08:51:18 +0000952 self.assertTrue("Spam" not in o.req.headers)
953 self.assertTrue("Spam" not in o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000954
955 # loop detection
956 req = Request(from_url)
Senthil Kumarane9da06f2009-07-19 04:20:12 +0000957 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000958 def redirect(h, req, url=to_url):
959 h.http_error_302(req, MockFile(), 302, "Blah",
960 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000961 # Note that the *original* request shares the same record of
962 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000963
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000964 # detect infinite loop redirect of a URL to itself
965 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000966 count = 0
Senthil Kumarane9da06f2009-07-19 04:20:12 +0000967 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000968 try:
969 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000970 redirect(h, req, "http://example.com/")
971 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000972 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000973 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000974 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000975
976 # detect endless non-repeating chain of redirects
977 req = Request(from_url, origin_req_host="example.com")
978 count = 0
Senthil Kumarane9da06f2009-07-19 04:20:12 +0000979 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000980 try:
981 while 1:
982 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000983 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000984 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000985 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000986 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000987
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000988 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000989 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +0000990 from http.cookiejar import CookieJar
991 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000992
993 cj = CookieJar()
994 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000995 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000996 hdeh = urllib.request.HTTPDefaultErrorHandler()
997 hrh = urllib.request.HTTPRedirectHandler()
998 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000999 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001000 o.open("http://www.example.com/")
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001001 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001002
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001003 def test_proxy(self):
1004 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001005 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001006 o.add_handler(ph)
1007 meth_spec = [
1008 [("http_open", "return response")]
1009 ]
1010 handlers = add_ordered_mock_handlers(o, meth_spec)
1011
1012 req = Request("http://acme.example.com/")
1013 self.assertEqual(req.get_host(), "acme.example.com")
1014 r = o.open(req)
1015 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1016
1017 self.assertEqual([(handlers[0], "http_open")],
1018 [tup[0:2] for tup in o.calls])
1019
Senthil Kumaran11301632009-10-11 06:07:46 +00001020 def test_proxy_no_proxy(self):
1021 os.environ['no_proxy'] = 'python.org'
1022 o = OpenerDirector()
1023 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1024 o.add_handler(ph)
1025 req = Request("http://www.perl.org/")
1026 self.assertEqual(req.get_host(), "www.perl.org")
1027 r = o.open(req)
1028 self.assertEqual(req.get_host(), "proxy.example.com")
1029 req = Request("http://www.python.org")
1030 self.assertEqual(req.get_host(), "www.python.org")
1031 r = o.open(req)
1032 self.assertEqual(req.get_host(), "www.python.org")
1033 del os.environ['no_proxy']
1034
Ronald Oussorene72e1612011-03-14 18:15:25 -04001035 def test_proxy_no_proxy_all(self):
1036 os.environ['no_proxy'] = '*'
1037 o = OpenerDirector()
1038 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1039 o.add_handler(ph)
1040 req = Request("http://www.python.org")
1041 self.assertEqual(req.get_host(), "www.python.org")
1042 r = o.open(req)
1043 self.assertEqual(req.get_host(), "www.python.org")
1044 del os.environ['no_proxy']
1045
Senthil Kumaran11301632009-10-11 06:07:46 +00001046
Senthil Kumaran0ac1f832009-07-26 12:39:47 +00001047 def test_proxy_https(self):
1048 o = OpenerDirector()
1049 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1050 o.add_handler(ph)
1051 meth_spec = [
1052 [("https_open", "return response")]
1053 ]
1054 handlers = add_ordered_mock_handlers(o, meth_spec)
1055
1056 req = Request("https://www.example.com/")
1057 self.assertEqual(req.get_host(), "www.example.com")
1058 r = o.open(req)
1059 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1060 self.assertEqual([(handlers[0], "https_open")],
1061 [tup[0:2] for tup in o.calls])
1062
Senthil Kumaran4b9fbeb2009-12-20 07:18:22 +00001063 def test_proxy_https_proxy_authorization(self):
1064 o = OpenerDirector()
1065 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1066 o.add_handler(ph)
1067 https_handler = MockHTTPSHandler()
1068 o.add_handler(https_handler)
1069 req = Request("https://www.example.com/")
1070 req.add_header("Proxy-Authorization","FooBar")
1071 req.add_header("User-Agent","Grail")
1072 self.assertEqual(req.get_host(), "www.example.com")
1073 self.assertIsNone(req._tunnel_host)
1074 r = o.open(req)
1075 # Verify Proxy-Authorization gets tunneled to request.
1076 # httpsconn req_headers do not have the Proxy-Authorization header but
1077 # the req will have.
1078 self.assertFalse(("Proxy-Authorization","FooBar") in
1079 https_handler.httpconn.req_headers)
1080 self.assertTrue(("User-Agent","Grail") in
1081 https_handler.httpconn.req_headers)
1082 self.assertIsNotNone(req._tunnel_host)
1083 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1084 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran0ac1f832009-07-26 12:39:47 +00001085
Ronald Oussorene72e1612011-03-14 18:15:25 -04001086 def test_osx_proxy_bypass(self):
1087 bypass = {
1088 'exclude_simple': False,
1089 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1090 '10.0/16']
1091 }
1092 # Check hosts that should trigger the proxy bypass
1093 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1094 '10.0.0.1'):
1095 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1096 'expected bypass of %s to be True' % host)
1097 # Check hosts that should not trigger the proxy bypass
1098 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1099 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1100 'expected bypass of %s to be False' % host)
1101
1102 # Check the exclude_simple flag
1103 bypass = {'exclude_simple': True, 'exceptions': []}
1104 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1105
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001106 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001107 opener = OpenerDirector()
1108 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001109 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001110 realm = "ACME Widget Store"
1111 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001112 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1113 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001114 opener.add_handler(auth_handler)
1115 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001116 self._test_basic_auth(opener, auth_handler, "Authorization",
1117 realm, http_handler, password_manager,
1118 "http://acme.example.com/protected",
1119 "http://acme.example.com/protected",
1120 )
1121
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001122 def test_basic_auth_with_single_quoted_realm(self):
1123 self.test_basic_auth(quote_char="'")
1124
Thomas Wouters477c8d52006-05-27 19:21:47 +00001125 def test_proxy_basic_auth(self):
1126 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001127 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001128 opener.add_handler(ph)
1129 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001130 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001131 realm = "ACME Networks"
1132 http_handler = MockHTTPHandler(
1133 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001134 opener.add_handler(auth_handler)
1135 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001136 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001137 realm, http_handler, password_manager,
1138 "http://acme.example.com:3128/protected",
1139 "proxy.example.com:3128",
1140 )
1141
1142 def test_basic_and_digest_auth_handlers(self):
1143 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1144 # response (http://python.org/sf/1479302), where it should instead
1145 # return None to allow another handler (especially
1146 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001147
1148 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1149 # try digest first (since it's the strongest auth scheme), so we record
1150 # order of calls here to check digest comes first:
1151 class RecordingOpenerDirector(OpenerDirector):
1152 def __init__(self):
1153 OpenerDirector.__init__(self)
1154 self.recorded = []
1155 def record(self, info):
1156 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001157 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001158 def http_error_401(self, *args, **kwds):
1159 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001160 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001161 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001162 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001163 def http_error_401(self, *args, **kwds):
1164 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001165 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001166 *args, **kwds)
1167
1168 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001169 password_manager = MockPasswordManager()
1170 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001171 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001172 realm = "ACME Networks"
1173 http_handler = MockHTTPHandler(
1174 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001175 opener.add_handler(basic_handler)
1176 opener.add_handler(digest_handler)
1177 opener.add_handler(http_handler)
1178
1179 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001180 self._test_basic_auth(opener, basic_handler, "Authorization",
1181 realm, http_handler, password_manager,
1182 "http://acme.example.com/protected",
1183 "http://acme.example.com/protected",
1184 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001185 # check digest was tried before basic (twice, because
1186 # _test_basic_auth called .open() twice)
1187 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001188
1189 def _test_basic_auth(self, opener, auth_handler, auth_header,
1190 realm, http_handler, password_manager,
1191 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001192 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001193 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001194
1195 # .add_password() fed through to password manager
1196 auth_handler.add_password(realm, request_url, user, password)
1197 self.assertEqual(realm, password_manager.realm)
1198 self.assertEqual(request_url, password_manager.url)
1199 self.assertEqual(user, password_manager.user)
1200 self.assertEqual(password, password_manager.password)
1201
1202 r = opener.open(request_url)
1203
1204 # should have asked the password manager for the username/password
1205 self.assertEqual(password_manager.target_realm, realm)
1206 self.assertEqual(password_manager.target_url, protected_url)
1207
1208 # expect one request without authorization, then one with
1209 self.assertEqual(len(http_handler.requests), 2)
1210 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001211 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001212 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001213 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001214 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1215 auth_hdr_value)
Senthil Kumaranefcd8832010-02-24 16:56:20 +00001216 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1217 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001218 # if the password manager can't find a password, the handler won't
1219 # handle the HTTP auth error
1220 password_manager.user = password_manager.password = None
1221 http_handler.reset()
1222 r = opener.open(request_url)
1223 self.assertEqual(len(http_handler.requests), 1)
1224 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1225
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001226class MiscTests(unittest.TestCase):
1227
1228 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001229 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1230 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001231 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001232 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001233 def bar_open(self): pass
1234
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001235 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001236
1237 o = build_opener(FooHandler, BarHandler)
1238 self.opener_has_handler(o, FooHandler)
1239 self.opener_has_handler(o, BarHandler)
1240
1241 # can take a mix of classes and instances
1242 o = build_opener(FooHandler, BarHandler())
1243 self.opener_has_handler(o, FooHandler)
1244 self.opener_has_handler(o, BarHandler)
1245
1246 # subclasses of default handlers override default handlers
1247 o = build_opener(MyHTTPHandler)
1248 self.opener_has_handler(o, MyHTTPHandler)
1249
1250 # a particular case of overriding: default handlers can be passed
1251 # in explicitly
1252 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001253 self.opener_has_handler(o, urllib.request.HTTPHandler)
1254 o = build_opener(urllib.request.HTTPHandler)
1255 self.opener_has_handler(o, urllib.request.HTTPHandler)
1256 o = build_opener(urllib.request.HTTPHandler())
1257 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001258
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001259 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001260 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001261 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1262 self.opener_has_handler(o, MyHTTPHandler)
1263 self.opener_has_handler(o, MyOtherHTTPHandler)
1264
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001265 def opener_has_handler(self, opener, handler_class):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001266 self.assertTrue(any(h.__class__ == handler_class
1267 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001268
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001269class RequestTests(unittest.TestCase):
1270
1271 def setUp(self):
1272 self.get = Request("http://www.python.org/~jeremy/")
1273 self.post = Request("http://www.python.org/~jeremy/",
1274 "data",
1275 headers={"X-Test": "test"})
1276
1277 def test_method(self):
1278 self.assertEqual("POST", self.post.get_method())
1279 self.assertEqual("GET", self.get.get_method())
1280
1281 def test_add_data(self):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001282 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001283 self.assertEqual("GET", self.get.get_method())
1284 self.get.add_data("spam")
Georg Brandlab91fde2009-08-13 08:51:18 +00001285 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001286 self.assertEqual("POST", self.get.get_method())
1287
1288 def test_get_full_url(self):
1289 self.assertEqual("http://www.python.org/~jeremy/",
1290 self.get.get_full_url())
1291
1292 def test_selector(self):
1293 self.assertEqual("/~jeremy/", self.get.get_selector())
1294 req = Request("http://www.python.org/")
1295 self.assertEqual("/", req.get_selector())
1296
1297 def test_get_type(self):
1298 self.assertEqual("http", self.get.get_type())
1299
1300 def test_get_host(self):
1301 self.assertEqual("www.python.org", self.get.get_host())
1302
1303 def test_get_host_unquote(self):
1304 req = Request("http://www.%70ython.org/")
1305 self.assertEqual("www.python.org", req.get_host())
1306
1307 def test_proxy(self):
Florent Xiclunab4efb3d2010-08-14 18:24:40 +00001308 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001309 self.get.set_proxy("www.perl.org", "http")
Georg Brandlab91fde2009-08-13 08:51:18 +00001310 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001311 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1312 self.assertEqual("www.perl.org", self.get.get_host())
1313
Senthil Kumaran4c88db72010-08-08 11:30:58 +00001314 def test_wrapped_url(self):
1315 req = Request("<URL:http://www.python.org>")
1316 self.assertEqual("www.python.org", req.get_host())
1317
1318 def test_urlwith_fragment(self):
1319 req = Request("http://www.python.org/?qs=query#fragment=true")
1320 self.assertEqual("/?qs=query", req.get_selector())
1321 req = Request("http://www.python.org/#fun=true")
1322 self.assertEqual("/", req.get_selector())
1323
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001324
1325def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001326 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001327 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001328 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001329 tests = (TrivialTests,
1330 OpenerDirectorTests,
1331 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001332 MiscTests,
1333 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001334 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001335
1336if __name__ == "__main__":
1337 test_main(verbose=True)