blob: 58ef83611deadce383cbdbdc3c61c553d0682987 [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
Ronald Oussorene72e1612011-03-14 18:15:25 -040010# The proxy bypass method imported below has logic specific to the OSX
11# proxy config data structure but is testable on all platforms.
12from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
guido@google.coma119df92011-03-29 11:41:02 -070013import urllib.error
Jeremy Hyltone3e61042001-05-09 15:50:25 +000014
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000015# XXX
16# Request
17# CacheFTPHandler (hard to write)
Thomas Wouters477c8d52006-05-27 19:21:47 +000018# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000019
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000020class TrivialTests(unittest.TestCase):
21 def test_trivial(self):
22 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000023
Jeremy Hylton1afc1692008-06-18 20:49:58 +000024 self.assertRaises(ValueError, urllib.request.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000025
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000026 # XXX Name hacking to get this to work on Windows.
Jeremy Hylton1afc1692008-06-18 20:49:58 +000027 fname = os.path.abspath(urllib.request.__file__).replace('\\', '/')
Senthil Kumarand587e302010-01-10 17:45:52 +000028
Senthil Kumarand587e302010-01-10 17:45:52 +000029 if os.name == 'nt':
30 file_url = "file:///%s" % fname
31 else:
32 file_url = "file://%s" % fname
33
Jeremy Hylton1afc1692008-06-18 20:49:58 +000034 f = urllib.request.urlopen(file_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000035
36 buf = f.read()
37 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000038
Georg Brandle1b13d22005-08-24 22:20:32 +000039 def test_parse_http_list(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000040 tests = [
41 ('a,b,c', ['a', 'b', 'c']),
42 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
43 ('a, b, "c", "d", "e,f", g, h',
44 ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
45 ('a="b\\"c", d="e\\,f", g="h\\\\i"',
46 ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
Georg Brandle1b13d22005-08-24 22:20:32 +000047 for string, list in tests:
Florent Xicluna419e3842010-08-08 16:16:07 +000048 self.assertEqual(urllib.request.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000049
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000050
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000051def test_request_headers_dict():
52 """
53 The Request.headers dictionary is not a documented interface. It should
54 stay that way, because the complete set of headers are only accessible
55 through the .get_header(), .has_header(), .header_items() interface.
56 However, .headers pre-dates those methods, and so real code will be using
57 the dictionary.
58
59 The introduction in 2.4 of those methods was a mistake for the same reason:
60 code that previously saw all (urllib2 user)-provided headers in .headers
61 now sees only a subset (and the function interface is ugly and incomplete).
62 A better change would have been to replace .headers dict with a dict
63 subclass (or UserDict.DictMixin instance?) that preserved the .headers
64 interface and also provided access to the "unredirected" headers. It's
65 probably too late to fix that, though.
66
67
68 Check .capitalize() case normalization:
69
70 >>> url = "http://example.com"
71 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
72 'blah'
73 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
74 'blah'
75
76 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
77 but that could be changed in future.
78
79 """
80
81def test_request_headers_methods():
82 """
83 Note the case normalization of header names here, to .capitalize()-case.
84 This should be preserved for backwards-compatibility. (In the HTTP case,
85 normalization to .title()-case is done by urllib2 before sending headers to
Georg Brandl24420152008-05-26 16:32:26 +000086 http.client).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000087
88 >>> url = "http://example.com"
89 >>> r = Request(url, headers={"Spam-eggs": "blah"})
90 >>> r.has_header("Spam-eggs")
91 True
92 >>> r.header_items()
93 [('Spam-eggs', 'blah')]
94 >>> r.add_header("Foo-Bar", "baz")
Guido van Rossumcc2b0162007-02-11 06:12:03 +000095 >>> items = sorted(r.header_items())
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000096 >>> items
97 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
98
99 Note that e.g. r.has_header("spam-EggS") is currently False, and
100 r.get_header("spam-EggS") returns None, but that could be changed in
101 future.
102
103 >>> r.has_header("Not-there")
104 False
Guido van Rossum7131f842007-02-09 20:13:25 +0000105 >>> print(r.get_header("Not-there"))
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000106 None
107 >>> r.get_header("Not-there", "default")
108 'default'
109
110 """
111
112
Thomas Wouters477c8d52006-05-27 19:21:47 +0000113def test_password_manager(self):
114 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000115 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000116 >>> add = mgr.add_password
117 >>> add("Some Realm", "http://example.com/", "joe", "password")
118 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
119 >>> add("c", "http://example.com/foo", "foo", "ni")
120 >>> add("c", "http://example.com/bar", "bar", "nini")
121 >>> add("b", "http://example.com/", "first", "blah")
122 >>> add("b", "http://example.com/", "second", "spam")
123 >>> add("a", "http://example.com", "1", "a")
124 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
125 >>> add("Some Realm", "d.example.com", "4", "d")
126 >>> add("Some Realm", "e.example.com:3128", "5", "e")
127
128 >>> mgr.find_user_password("Some Realm", "example.com")
129 ('joe', 'password')
130 >>> mgr.find_user_password("Some Realm", "http://example.com")
131 ('joe', 'password')
132 >>> mgr.find_user_password("Some Realm", "http://example.com/")
133 ('joe', 'password')
134 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
135 ('joe', 'password')
136 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
137 ('joe', 'password')
138 >>> mgr.find_user_password("c", "http://example.com/foo")
139 ('foo', 'ni')
140 >>> mgr.find_user_password("c", "http://example.com/bar")
141 ('bar', 'nini')
142
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000143 Actually, this is really undefined ATM
144## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000145
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000146## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
147## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000148
149 Use latest add_password() in case of conflict:
150
151 >>> mgr.find_user_password("b", "http://example.com/")
152 ('second', 'spam')
153
154 No special relationship between a.example.com and example.com:
155
156 >>> mgr.find_user_password("a", "http://example.com/")
157 ('1', 'a')
158 >>> mgr.find_user_password("a", "http://a.example.com/")
159 (None, None)
160
161 Ports:
162
163 >>> mgr.find_user_password("Some Realm", "c.example.com")
164 (None, None)
165 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
166 ('3', 'c')
167 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
168 ('3', 'c')
169 >>> mgr.find_user_password("Some Realm", "d.example.com")
170 ('4', 'd')
171 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
172 ('5', 'e')
173
174 """
175 pass
176
177
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000178def test_password_manager_default_port(self):
179 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000180 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000181 >>> add = mgr.add_password
182
183 The point to note here is that we can't guess the default port if there's
184 no scheme. This applies to both add_password and find_user_password.
185
186 >>> add("f", "http://g.example.com:80", "10", "j")
187 >>> add("g", "http://h.example.com", "11", "k")
188 >>> add("h", "i.example.com:80", "12", "l")
189 >>> add("i", "j.example.com", "13", "m")
190 >>> mgr.find_user_password("f", "g.example.com:100")
191 (None, None)
192 >>> mgr.find_user_password("f", "g.example.com:80")
193 ('10', 'j')
194 >>> mgr.find_user_password("f", "g.example.com")
195 (None, None)
196 >>> mgr.find_user_password("f", "http://g.example.com:100")
197 (None, None)
198 >>> mgr.find_user_password("f", "http://g.example.com:80")
199 ('10', 'j')
200 >>> mgr.find_user_password("f", "http://g.example.com")
201 ('10', 'j')
202 >>> mgr.find_user_password("g", "h.example.com")
203 ('11', 'k')
204 >>> mgr.find_user_password("g", "h.example.com:80")
205 ('11', 'k')
206 >>> mgr.find_user_password("g", "http://h.example.com:80")
207 ('11', 'k')
208 >>> mgr.find_user_password("h", "i.example.com")
209 (None, None)
210 >>> mgr.find_user_password("h", "i.example.com:80")
211 ('12', 'l')
212 >>> mgr.find_user_password("h", "http://i.example.com:80")
213 ('12', 'l')
214 >>> mgr.find_user_password("i", "j.example.com")
215 ('13', 'm')
216 >>> mgr.find_user_password("i", "j.example.com:80")
217 (None, None)
218 >>> mgr.find_user_password("i", "http://j.example.com")
219 ('13', 'm')
220 >>> mgr.find_user_password("i", "http://j.example.com:80")
221 (None, None)
222
223 """
224
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000225class MockOpener:
226 addheaders = []
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000227 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
228 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000229 def error(self, proto, *args):
230 self.proto, self.args = proto, args
231
232class MockFile:
233 def read(self, count=None): pass
234 def readline(self, count=None): pass
235 def close(self): pass
236
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000237class MockHeaders(dict):
238 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000239 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000240
Guido van Rossum34d19282007-08-09 01:03:29 +0000241class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000242 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000243 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000244 self.code, self.msg, self.headers, self.url = code, msg, headers, url
245 def info(self):
246 return self.headers
247 def geturl(self):
248 return self.url
249
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000250class MockCookieJar:
251 def add_cookie_header(self, request):
252 self.ach_req = request
253 def extract_cookies(self, response, request):
254 self.ec_req, self.ec_r = request, response
255
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000256class FakeMethod:
257 def __init__(self, meth_name, action, handle):
258 self.meth_name = meth_name
259 self.handle = handle
260 self.action = action
261 def __call__(self, *args):
262 return self.handle(self.meth_name, self.action, *args)
263
Senthil Kumaran47fff872009-12-20 07:10:31 +0000264class MockHTTPResponse(io.IOBase):
265 def __init__(self, fp, msg, status, reason):
266 self.fp = fp
267 self.msg = msg
268 self.status = status
269 self.reason = reason
270 self.code = 200
271
272 def read(self):
273 return ''
274
275 def info(self):
276 return {}
277
278 def geturl(self):
279 return self.url
280
281
282class MockHTTPClass:
283 def __init__(self):
284 self.level = 0
285 self.req_headers = []
286 self.data = None
287 self.raise_on_endheaders = False
288 self._tunnel_headers = {}
289
290 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
291 self.host = host
292 self.timeout = timeout
293 return self
294
295 def set_debuglevel(self, level):
296 self.level = level
297
298 def set_tunnel(self, host, port=None, headers=None):
299 self._tunnel_host = host
300 self._tunnel_port = port
301 if headers:
302 self._tunnel_headers = headers
303 else:
304 self._tunnel_headers.clear()
305
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000306 def request(self, method, url, body=None, headers=None):
Senthil Kumaran47fff872009-12-20 07:10:31 +0000307 self.method = method
308 self.selector = url
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000309 if headers is not None:
310 self.req_headers += headers.items()
Senthil Kumaran47fff872009-12-20 07:10:31 +0000311 self.req_headers.sort()
312 if body:
313 self.data = body
314 if self.raise_on_endheaders:
315 import socket
316 raise socket.error()
317 def getresponse(self):
318 return MockHTTPResponse(MockFile(), {}, 200, "OK")
319
Victor Stinnera4c45d72011-06-17 14:01:18 +0200320 def close(self):
321 pass
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 Kumaran47fff872009-12-20 07:10:31 +0000430class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
431 # Useful for testing the Proxy-Authorization request by verifying the
432 # properties of httpcon
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000433
434 def __init__(self):
435 urllib.request.AbstractHTTPHandler.__init__(self)
436 self.httpconn = MockHTTPClass()
437
Senthil Kumaran47fff872009-12-20 07:10:31 +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)
Ezio Melottie9615932010-01-24 19:26:24 +0000594 self.assertIsInstance(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)
Ezio Melottie9615932010-01-24 19:26:24 +0000599 self.assertIsInstance(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
Benjamin Petersonc9c0f202009-06-30 23:06:06 +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):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000607 try:
608 path.encode("utf8")
609 except UnicodeEncodeError:
610 raise unittest.SkipTest("path is not encodable to utf8")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000611 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000612 if os.name == "nt" and urlpath.startswith("///"):
613 urlpath = urlpath[2:]
614 # XXX don't ask me about the mac...
615 return urlpath
616
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000617class HandlerTests(unittest.TestCase):
618
619 def test_ftp(self):
620 class MockFTPWrapper:
621 def __init__(self, data): self.data = data
622 def retrfile(self, filename, filetype):
623 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000624 return io.StringIO(self.data), len(self.data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000625
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000626 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000627 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000628 def connect_ftp(self, user, passwd, host, port, dirs,
629 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000630 self.user, self.passwd = user, passwd
631 self.host, self.port = host, port
632 self.dirs = dirs
633 self.ftpwrapper = MockFTPWrapper(self.data)
634 return self.ftpwrapper
635
Georg Brandlf78e02b2008-06-10 17:40:04 +0000636 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000637 data = "rheum rhaponicum"
638 h = NullFTPHandler(data)
639 o = h.parent = MockOpener()
640
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000641 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000642 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000643 "localhost", ftplib.FTP_PORT, "", "", "I",
644 ["foo", "bar"], "baz.html", "text/html"),
645 ("ftp://parrot@localhost/foo/bar/baz.html",
646 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
647 ["foo", "bar"], "baz.html", "text/html"),
648 ("ftp://%25parrot@localhost/foo/bar/baz.html",
649 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
650 ["foo", "bar"], "baz.html", "text/html"),
651 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
652 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000653 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000654 ("ftp://localhost:80/foo/bar/",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000655 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000656 ["foo", "bar"], "", None),
657 ("ftp://localhost/baz.gif;type=a",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000658 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000659 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000660 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000661 req = Request(url)
662 req.timeout = None
663 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000664 # ftp authentication not yet implemented by FTPHandler
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000665 self.assertEqual(h.user, user)
666 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000667 self.assertEqual(h.host, socket.gethostbyname(host))
668 self.assertEqual(h.port, port)
669 self.assertEqual(h.dirs, dirs)
670 self.assertEqual(h.ftpwrapper.filename, filename)
671 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000672 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000673 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000674 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000675
676 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000677 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000678 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000679 o = h.parent = MockOpener()
680
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000681 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000682 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000683 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000684 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000685 "file://localhost%s" % urlpath,
686 "file://%s" % urlpath,
687 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000688 ]
689 try:
690 localaddr = socket.gethostbyname(socket.gethostname())
691 except socket.gaierror:
692 localaddr = ''
693 if localaddr:
694 urls.append("file://%s%s" % (localaddr, urlpath))
695
696 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000697 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000698 try:
699 try:
700 f.write(towrite)
701 finally:
702 f.close()
703
704 r = h.file_open(Request(url))
705 try:
706 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000707 headers = r.info()
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000708 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000709 finally:
710 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000711 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000712 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000713 finally:
714 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000715 self.assertEqual(data, towrite)
716 self.assertEqual(headers["Content-type"], "text/plain")
717 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000718 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000719 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000720
721 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000722 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000723 "file:///file_does_not_exist.txt",
724 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
725 os.getcwd(), TESTFN),
726 "file://somerandomhost.ontheinternet.com%s/%s" %
727 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000728 ]:
729 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000730 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000731 try:
732 f.write(towrite)
733 finally:
734 f.close()
735
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000736 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000737 h.file_open, Request(url))
738 finally:
739 os.remove(TESTFN)
740
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000741 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000742 o = h.parent = MockOpener()
743 # XXXX why does // mean ftp (and /// mean not ftp!), and where
744 # is file: scheme specified? I think this is really a bug, and
745 # what was intended was to distinguish between URLs like:
746 # file:/blah.txt (a file)
747 # file://localhost/blah.txt (a file)
748 # file:///blah.txt (a file)
749 # file://ftp.example.com/blah.txt (an ftp URL)
750 for url, ftp in [
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000751 ("file://ftp.example.com//foo.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000752 ("file://ftp.example.com///foo.txt", False),
753# XXXX bug: fails with OSError, should be URLError
754 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000755 ("file://somehost//foo/something.txt", False),
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000756 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000757 ]:
758 req = Request(url)
759 try:
760 h.file_open(req)
761 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000762 except (urllib.error.URLError, OSError):
Florent Xicluna419e3842010-08-08 16:16:07 +0000763 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000764 else:
Florent Xicluna419e3842010-08-08 16:16:07 +0000765 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000766 self.assertEqual(req.type, "ftp")
Łukasz Langad7e81cc2011-01-09 18:18:53 +0000767 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000768
769 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000770
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000771 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000772 o = h.parent = MockOpener()
773
774 url = "http://example.com/"
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000775 for method, data in [("GET", None), ("POST", b"blah")]:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000776 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000777 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000778 req.add_unredirected_header("Spam", "eggs")
779 http = MockHTTPClass()
780 r = h.do_open(http, req)
781
782 # result attributes
783 r.read; r.readline # wrapped MockFile methods
784 r.info; r.geturl # addinfourl methods
785 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
786 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000787 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000788 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000789
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000790 self.assertEqual(http.host, "example.com")
791 self.assertEqual(http.level, 0)
792 self.assertEqual(http.method, method)
793 self.assertEqual(http.selector, "/")
794 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000795 [("Connection", "close"),
796 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000797 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000798
799 # check socket.error converted to URLError
800 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000801 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000802
Senthil Kumaran29333122011-02-11 11:25:47 +0000803 # Check for TypeError on POST data which is str.
804 req = Request("http://example.com/","badpost")
805 self.assertRaises(TypeError, h.do_request_, req)
806
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000807 # check adding of standard headers
808 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000809 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000810 req = Request("http://example.com/", data)
811 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000812 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000813 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000814 self.assertNotIn("Content-length", req.unredirected_hdrs)
815 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000816 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000817 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
818 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000819 "application/x-www-form-urlencoded")
820 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000821 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
822 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000823
824 # don't clobber existing headers
825 req.add_unredirected_header("Content-length", "foo")
826 req.add_unredirected_header("Content-type", "bar")
827 req.add_unredirected_header("Host", "baz")
828 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000829 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000830 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
831 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000832 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
833 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000834
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000835 # Check iterable body support
836 def iterable_body():
837 yield b"one"
838 yield b"two"
839 yield b"three"
840
841 for headers in {}, {"Content-Length": 11}:
842 req = Request("http://example.com/", iterable_body(), headers)
843 if not headers:
844 # Having an iterable body without a Content-Length should
845 # raise an exception
846 self.assertRaises(ValueError, h.do_request_, req)
847 else:
848 newreq = h.do_request_(req)
849
Senthil Kumaran29333122011-02-11 11:25:47 +0000850 # A file object.
851 # Test only Content-Length attribute of request.
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000852
Senthil Kumaran29333122011-02-11 11:25:47 +0000853 file_obj = io.BytesIO()
854 file_obj.write(b"Something\nSomething\nSomething\n")
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000855
856 for headers in {}, {"Content-Length": 30}:
857 req = Request("http://example.com/", file_obj, headers)
858 if not headers:
859 # Having an iterable body without a Content-Length should
860 # raise an exception
861 self.assertRaises(ValueError, h.do_request_, req)
862 else:
863 newreq = h.do_request_(req)
864 self.assertEqual(int(newreq.get_header('Content-length')),30)
865
866 file_obj.close()
867
868 # array.array Iterable - Content Length is calculated
869
870 iterable_array = array.array("I",[1,2,3,4])
871
872 for headers in {}, {"Content-Length": 16}:
873 req = Request("http://example.com/", iterable_array, headers)
874 newreq = h.do_request_(req)
875 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000876
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000877 def test_http_doubleslash(self):
878 # Checks the presence of any unnecessary double slash in url does not
879 # break anything. Previously, a double slash directly after the host
880 # could could cause incorrect parsing.
881 h = urllib.request.AbstractHTTPHandler()
882 o = h.parent = MockOpener()
883
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000884 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000885 ds_urls = [
886 "http://example.com/foo/bar/baz.html",
887 "http://example.com//foo/bar/baz.html",
888 "http://example.com/foo//bar/baz.html",
889 "http://example.com/foo/bar//baz.html"
890 ]
891
892 for ds_url in ds_urls:
893 ds_req = Request(ds_url, data)
894
895 # Check whether host is determined correctly if there is no proxy
896 np_ds_req = h.do_request_(ds_req)
897 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
898
899 # Check whether host is determined correctly if there is a proxy
900 ds_req.set_proxy("someproxy:3128",None)
901 p_ds_req = h.do_request_(ds_req)
902 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
903
Senthil Kumaranc2958622010-11-22 04:48:26 +0000904 def test_fixpath_in_weirdurls(self):
905 # Issue4493: urllib2 to supply '/' when to urls where path does not
906 # start with'/'
907
908 h = urllib.request.AbstractHTTPHandler()
909 o = h.parent = MockOpener()
910
911 weird_url = 'http://www.python.org?getspam'
912 req = Request(weird_url)
913 newreq = h.do_request_(req)
914 self.assertEqual(newreq.host,'www.python.org')
915 self.assertEqual(newreq.selector,'/?getspam')
916
917 url_without_path = 'http://www.python.org'
918 req = Request(url_without_path)
919 newreq = h.do_request_(req)
920 self.assertEqual(newreq.host,'www.python.org')
921 self.assertEqual(newreq.selector,'')
922
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000923
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000924 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000925 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000926 o = h.parent = MockOpener()
927
928 url = "http://example.com/"
929 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000930 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000931 r = MockResponse(200, "OK", {}, "", url)
932 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000933 self.assertIs(r, newr)
934 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000935 r = MockResponse(202, "Accepted", {}, "", url)
936 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000937 self.assertIs(r, newr)
938 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000939 r = MockResponse(206, "Partial content", {}, "", url)
940 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000941 self.assertIs(r, newr)
942 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000943 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000944 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000945 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000946 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000947 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000948
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000949 def test_cookies(self):
950 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000951 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000952 o = h.parent = MockOpener()
953
954 req = Request("http://example.com/")
955 r = MockResponse(200, "OK", {}, "")
956 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000957 self.assertIs(cj.ach_req, req)
958 self.assertIs(cj.ach_req, newreq)
959 self.assertEqual(req.get_origin_req_host(), "example.com")
960 self.assertFalse(req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000961 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000962 self.assertIs(cj.ec_req, req)
963 self.assertIs(cj.ec_r, r)
964 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000965
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000966 def test_redirect(self):
967 from_url = "http://example.com/a.html"
968 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000969 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000970 o = h.parent = MockOpener()
971
972 # ordinary redirect behaviour
973 for code in 301, 302, 303, 307:
974 for data in None, "blah\nblah\n":
975 method = getattr(h, "http_error_%s" % code)
976 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000977 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000978 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +0000979 if data is not None:
980 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000981 req.add_unredirected_header("Spam", "spam")
982 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000983 method(req, MockFile(), code, "Blah",
984 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000985 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000986 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000987 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000988 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000989 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000990 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000991 except AttributeError:
Florent Xicluna419e3842010-08-08 16:16:07 +0000992 self.assertFalse(o.req.has_data())
Christian Heimes77c02eb2008-02-09 02:18:51 +0000993
994 # now it's a GET, there should not be headers regarding content
995 # (possibly dragged from before being a POST)
996 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +0000997 self.assertNotIn("content-length", headers)
998 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +0000999
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001000 self.assertEqual(o.req.headers["Nonsense"],
1001 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001002 self.assertNotIn("Spam", o.req.headers)
1003 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001004
1005 # loop detection
1006 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001007 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001008 def redirect(h, req, url=to_url):
1009 h.http_error_302(req, MockFile(), 302, "Blah",
1010 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001011 # Note that the *original* request shares the same record of
1012 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001013
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001014 # detect infinite loop redirect of a URL to itself
1015 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001016 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001017 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001018 try:
1019 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001020 redirect(h, req, "http://example.com/")
1021 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001022 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001023 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001024 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001025
1026 # detect endless non-repeating chain of redirects
1027 req = Request(from_url, origin_req_host="example.com")
1028 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001029 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001030 try:
1031 while 1:
1032 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001033 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001034 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001035 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001036 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001037
guido@google.coma119df92011-03-29 11:41:02 -07001038
1039 def test_invalid_redirect(self):
1040 from_url = "http://example.com/a.html"
1041 valid_schemes = ['http','https','ftp']
1042 invalid_schemes = ['file','imap','ldap']
1043 schemeless_url = "example.com/b.html"
1044 h = urllib.request.HTTPRedirectHandler()
1045 o = h.parent = MockOpener()
1046 req = Request(from_url)
1047 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1048
1049 for scheme in invalid_schemes:
1050 invalid_url = scheme + '://' + schemeless_url
1051 self.assertRaises(urllib.error.HTTPError, h.http_error_302,
1052 req, MockFile(), 302, "Security Loophole",
1053 MockHeaders({"location": invalid_url}))
1054
1055 for scheme in valid_schemes:
1056 valid_url = scheme + '://' + schemeless_url
1057 h.http_error_302(req, MockFile(), 302, "That's fine",
1058 MockHeaders({"location": valid_url}))
1059 self.assertEqual(o.req.get_full_url(), valid_url)
1060
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001061 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001062 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001063 from http.cookiejar import CookieJar
1064 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001065
1066 cj = CookieJar()
1067 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001068 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001069 hdeh = urllib.request.HTTPDefaultErrorHandler()
1070 hrh = urllib.request.HTTPRedirectHandler()
1071 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001072 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001073 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001074 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001075
Senthil Kumaran26430412011-04-13 07:01:19 +08001076 def test_redirect_fragment(self):
1077 redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
1078 hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
1079 hdeh = urllib.request.HTTPDefaultErrorHandler()
1080 hrh = urllib.request.HTTPRedirectHandler()
1081 o = build_test_opener(hh, hdeh, hrh)
1082 fp = o.open('http://www.example.com')
1083 self.assertEqual(fp.geturl(), redirected_url.strip())
1084
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001085 def test_proxy(self):
1086 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001087 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001088 o.add_handler(ph)
1089 meth_spec = [
1090 [("http_open", "return response")]
1091 ]
1092 handlers = add_ordered_mock_handlers(o, meth_spec)
1093
1094 req = Request("http://acme.example.com/")
1095 self.assertEqual(req.get_host(), "acme.example.com")
1096 r = o.open(req)
1097 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1098
1099 self.assertEqual([(handlers[0], "http_open")],
1100 [tup[0:2] for tup in o.calls])
1101
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001102 def test_proxy_no_proxy(self):
1103 os.environ['no_proxy'] = 'python.org'
1104 o = OpenerDirector()
1105 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1106 o.add_handler(ph)
1107 req = Request("http://www.perl.org/")
1108 self.assertEqual(req.get_host(), "www.perl.org")
1109 r = o.open(req)
1110 self.assertEqual(req.get_host(), "proxy.example.com")
1111 req = Request("http://www.python.org")
1112 self.assertEqual(req.get_host(), "www.python.org")
1113 r = o.open(req)
1114 self.assertEqual(req.get_host(), "www.python.org")
1115 del os.environ['no_proxy']
1116
Ronald Oussorene72e1612011-03-14 18:15:25 -04001117 def test_proxy_no_proxy_all(self):
1118 os.environ['no_proxy'] = '*'
1119 o = OpenerDirector()
1120 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1121 o.add_handler(ph)
1122 req = Request("http://www.python.org")
1123 self.assertEqual(req.get_host(), "www.python.org")
1124 r = o.open(req)
1125 self.assertEqual(req.get_host(), "www.python.org")
1126 del os.environ['no_proxy']
1127
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001128
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001129 def test_proxy_https(self):
1130 o = OpenerDirector()
1131 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1132 o.add_handler(ph)
1133 meth_spec = [
1134 [("https_open", "return response")]
1135 ]
1136 handlers = add_ordered_mock_handlers(o, meth_spec)
1137
1138 req = Request("https://www.example.com/")
1139 self.assertEqual(req.get_host(), "www.example.com")
1140 r = o.open(req)
1141 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1142 self.assertEqual([(handlers[0], "https_open")],
1143 [tup[0:2] for tup in o.calls])
1144
Senthil Kumaran47fff872009-12-20 07:10:31 +00001145 def test_proxy_https_proxy_authorization(self):
1146 o = OpenerDirector()
1147 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1148 o.add_handler(ph)
1149 https_handler = MockHTTPSHandler()
1150 o.add_handler(https_handler)
1151 req = Request("https://www.example.com/")
1152 req.add_header("Proxy-Authorization","FooBar")
1153 req.add_header("User-Agent","Grail")
1154 self.assertEqual(req.get_host(), "www.example.com")
1155 self.assertIsNone(req._tunnel_host)
1156 r = o.open(req)
1157 # Verify Proxy-Authorization gets tunneled to request.
1158 # httpsconn req_headers do not have the Proxy-Authorization header but
1159 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001160 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001161 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001162 self.assertIn(("User-Agent","Grail"),
1163 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001164 self.assertIsNotNone(req._tunnel_host)
1165 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1166 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001167
Ronald Oussorene72e1612011-03-14 18:15:25 -04001168 def test_osx_proxy_bypass(self):
1169 bypass = {
1170 'exclude_simple': False,
1171 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1172 '10.0/16']
1173 }
1174 # Check hosts that should trigger the proxy bypass
1175 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1176 '10.0.0.1'):
1177 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1178 'expected bypass of %s to be True' % host)
1179 # Check hosts that should not trigger the proxy bypass
1180 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1181 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1182 'expected bypass of %s to be False' % host)
1183
1184 # Check the exclude_simple flag
1185 bypass = {'exclude_simple': True, 'exceptions': []}
1186 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1187
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001188 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001189 opener = OpenerDirector()
1190 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001191 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001192 realm = "ACME Widget Store"
1193 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001194 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1195 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001196 opener.add_handler(auth_handler)
1197 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001198 self._test_basic_auth(opener, auth_handler, "Authorization",
1199 realm, http_handler, password_manager,
1200 "http://acme.example.com/protected",
1201 "http://acme.example.com/protected",
1202 )
1203
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001204 def test_basic_auth_with_single_quoted_realm(self):
1205 self.test_basic_auth(quote_char="'")
1206
Thomas Wouters477c8d52006-05-27 19:21:47 +00001207 def test_proxy_basic_auth(self):
1208 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001209 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001210 opener.add_handler(ph)
1211 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001212 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001213 realm = "ACME Networks"
1214 http_handler = MockHTTPHandler(
1215 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001216 opener.add_handler(auth_handler)
1217 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001218 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001219 realm, http_handler, password_manager,
1220 "http://acme.example.com:3128/protected",
1221 "proxy.example.com:3128",
1222 )
1223
1224 def test_basic_and_digest_auth_handlers(self):
1225 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
1226 # response (http://python.org/sf/1479302), where it should instead
1227 # return None to allow another handler (especially
1228 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001229
1230 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1231 # try digest first (since it's the strongest auth scheme), so we record
1232 # order of calls here to check digest comes first:
1233 class RecordingOpenerDirector(OpenerDirector):
1234 def __init__(self):
1235 OpenerDirector.__init__(self)
1236 self.recorded = []
1237 def record(self, info):
1238 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001239 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001240 def http_error_401(self, *args, **kwds):
1241 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001242 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001243 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001244 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001245 def http_error_401(self, *args, **kwds):
1246 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001247 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001248 *args, **kwds)
1249
1250 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001251 password_manager = MockPasswordManager()
1252 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001253 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001254 realm = "ACME Networks"
1255 http_handler = MockHTTPHandler(
1256 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001257 opener.add_handler(basic_handler)
1258 opener.add_handler(digest_handler)
1259 opener.add_handler(http_handler)
1260
1261 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001262 self._test_basic_auth(opener, basic_handler, "Authorization",
1263 realm, http_handler, password_manager,
1264 "http://acme.example.com/protected",
1265 "http://acme.example.com/protected",
1266 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001267 # check digest was tried before basic (twice, because
1268 # _test_basic_auth called .open() twice)
1269 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001270
1271 def _test_basic_auth(self, opener, auth_handler, auth_header,
1272 realm, http_handler, password_manager,
1273 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001274 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001275 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001276
1277 # .add_password() fed through to password manager
1278 auth_handler.add_password(realm, request_url, user, password)
1279 self.assertEqual(realm, password_manager.realm)
1280 self.assertEqual(request_url, password_manager.url)
1281 self.assertEqual(user, password_manager.user)
1282 self.assertEqual(password, password_manager.password)
1283
1284 r = opener.open(request_url)
1285
1286 # should have asked the password manager for the username/password
1287 self.assertEqual(password_manager.target_realm, realm)
1288 self.assertEqual(password_manager.target_url, protected_url)
1289
1290 # expect one request without authorization, then one with
1291 self.assertEqual(len(http_handler.requests), 2)
1292 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001293 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001294 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001295 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001296 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1297 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001298 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1299 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001300 # if the password manager can't find a password, the handler won't
1301 # handle the HTTP auth error
1302 password_manager.user = password_manager.password = None
1303 http_handler.reset()
1304 r = opener.open(request_url)
1305 self.assertEqual(len(http_handler.requests), 1)
1306 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1307
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001308class MiscTests(unittest.TestCase):
1309
1310 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001311 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1312 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001313 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001314 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001315 def bar_open(self): pass
1316
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001317 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001318
1319 o = build_opener(FooHandler, BarHandler)
1320 self.opener_has_handler(o, FooHandler)
1321 self.opener_has_handler(o, BarHandler)
1322
1323 # can take a mix of classes and instances
1324 o = build_opener(FooHandler, BarHandler())
1325 self.opener_has_handler(o, FooHandler)
1326 self.opener_has_handler(o, BarHandler)
1327
1328 # subclasses of default handlers override default handlers
1329 o = build_opener(MyHTTPHandler)
1330 self.opener_has_handler(o, MyHTTPHandler)
1331
1332 # a particular case of overriding: default handlers can be passed
1333 # in explicitly
1334 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001335 self.opener_has_handler(o, urllib.request.HTTPHandler)
1336 o = build_opener(urllib.request.HTTPHandler)
1337 self.opener_has_handler(o, urllib.request.HTTPHandler)
1338 o = build_opener(urllib.request.HTTPHandler())
1339 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001340
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001341 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001342 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001343 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1344 self.opener_has_handler(o, MyHTTPHandler)
1345 self.opener_has_handler(o, MyOtherHTTPHandler)
1346
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001347 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001348 self.assertTrue(any(h.__class__ == handler_class
1349 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001350
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001351class RequestTests(unittest.TestCase):
1352
1353 def setUp(self):
1354 self.get = Request("http://www.python.org/~jeremy/")
1355 self.post = Request("http://www.python.org/~jeremy/",
1356 "data",
1357 headers={"X-Test": "test"})
1358
1359 def test_method(self):
1360 self.assertEqual("POST", self.post.get_method())
1361 self.assertEqual("GET", self.get.get_method())
1362
1363 def test_add_data(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001364 self.assertFalse(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001365 self.assertEqual("GET", self.get.get_method())
1366 self.get.add_data("spam")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001367 self.assertTrue(self.get.has_data())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001368 self.assertEqual("POST", self.get.get_method())
1369
1370 def test_get_full_url(self):
1371 self.assertEqual("http://www.python.org/~jeremy/",
1372 self.get.get_full_url())
1373
1374 def test_selector(self):
1375 self.assertEqual("/~jeremy/", self.get.get_selector())
1376 req = Request("http://www.python.org/")
1377 self.assertEqual("/", req.get_selector())
1378
1379 def test_get_type(self):
1380 self.assertEqual("http", self.get.get_type())
1381
1382 def test_get_host(self):
1383 self.assertEqual("www.python.org", self.get.get_host())
1384
1385 def test_get_host_unquote(self):
1386 req = Request("http://www.%70ython.org/")
1387 self.assertEqual("www.python.org", req.get_host())
1388
1389 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001390 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001391 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001392 self.assertTrue(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001393 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1394 self.assertEqual("www.perl.org", self.get.get_host())
1395
Senthil Kumarand95cc752010-08-08 11:27:53 +00001396 def test_wrapped_url(self):
1397 req = Request("<URL:http://www.python.org>")
1398 self.assertEqual("www.python.org", req.get_host())
1399
Senthil Kumaran26430412011-04-13 07:01:19 +08001400 def test_url_fragment(self):
Senthil Kumarand95cc752010-08-08 11:27:53 +00001401 req = Request("http://www.python.org/?qs=query#fragment=true")
1402 self.assertEqual("/?qs=query", req.get_selector())
1403 req = Request("http://www.python.org/#fun=true")
1404 self.assertEqual("/", req.get_selector())
1405
Senthil Kumaran26430412011-04-13 07:01:19 +08001406 # Issue 11703: geturl() omits fragment in the original URL.
1407 url = 'http://docs.python.org/library/urllib2.html#OK'
1408 req = Request(url)
1409 self.assertEqual(req.get_full_url(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001410
1411def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001412 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001413 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001414 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001415 tests = (TrivialTests,
1416 OpenerDirectorTests,
1417 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001418 MiscTests,
1419 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001420 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001421
1422if __name__ == "__main__":
1423 test_main(verbose=True)