blob: 01f4dc423e06bb1a7f6e08f2a721dcadd7b61369 [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
Senthil Kumaran4de00a22011-05-11 21:17:57 +08008import sys
Jeremy Hyltone3e61042001-05-09 15:50:25 +00009
Jeremy Hylton1afc1692008-06-18 20:49:58 +000010import urllib.request
Ronald Oussorene72e1612011-03-14 18:15:25 -040011# The proxy bypass method imported below has logic specific to the OSX
12# proxy config data structure but is testable on all platforms.
13from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
guido@google.coma119df92011-03-29 11:41:02 -070014import urllib.error
Jeremy Hyltone3e61042001-05-09 15:50:25 +000015
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000016# XXX
17# Request
18# CacheFTPHandler (hard to write)
Thomas Wouters477c8d52006-05-27 19:21:47 +000019# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000020
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000021class TrivialTests(unittest.TestCase):
Senthil Kumaran6c5bd402011-11-01 23:20:31 +080022
23 def test___all__(self):
24 # Verify which names are exposed
25 for module in 'request', 'response', 'parse', 'error', 'robotparser':
26 context = {}
27 exec('from urllib.%s import *' % module, context)
28 del context['__builtins__']
Florent Xicluna3dbb1f12011-11-04 22:15:37 +010029 if module == 'request' and os.name == 'nt':
30 u, p = context.pop('url2pathname'), context.pop('pathname2url')
31 self.assertEqual(u.__module__, 'nturl2path')
32 self.assertEqual(p.__module__, 'nturl2path')
Senthil Kumaran6c5bd402011-11-01 23:20:31 +080033 for k, v in context.items():
34 self.assertEqual(v.__module__, 'urllib.%s' % module,
35 "%r is exposed in 'urllib.%s' but defined in %r" %
36 (k, module, v.__module__))
37
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000038 def test_trivial(self):
39 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000040
Jeremy Hylton1afc1692008-06-18 20:49:58 +000041 self.assertRaises(ValueError, urllib.request.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000042
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000043 # XXX Name hacking to get this to work on Windows.
Jeremy Hylton1afc1692008-06-18 20:49:58 +000044 fname = os.path.abspath(urllib.request.__file__).replace('\\', '/')
Senthil Kumarand587e302010-01-10 17:45:52 +000045
Senthil Kumarand587e302010-01-10 17:45:52 +000046 if os.name == 'nt':
47 file_url = "file:///%s" % fname
48 else:
49 file_url = "file://%s" % fname
50
Jeremy Hylton1afc1692008-06-18 20:49:58 +000051 f = urllib.request.urlopen(file_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000052
53 buf = f.read()
54 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000055
Georg Brandle1b13d22005-08-24 22:20:32 +000056 def test_parse_http_list(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +000057 tests = [
58 ('a,b,c', ['a', 'b', 'c']),
59 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
60 ('a, b, "c", "d", "e,f", g, h',
61 ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
62 ('a="b\\"c", d="e\\,f", g="h\\\\i"',
63 ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
Georg Brandle1b13d22005-08-24 22:20:32 +000064 for string, list in tests:
Florent Xicluna419e3842010-08-08 16:16:07 +000065 self.assertEqual(urllib.request.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000066
Senthil Kumaran843fae92013-03-19 13:43:42 -070067 def test_URLError_reasonstr(self):
68 err = urllib.error.URLError('reason')
69 self.assertIn(err.reason, str(err))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000070
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000071def test_request_headers_dict():
72 """
73 The Request.headers dictionary is not a documented interface. It should
74 stay that way, because the complete set of headers are only accessible
75 through the .get_header(), .has_header(), .header_items() interface.
76 However, .headers pre-dates those methods, and so real code will be using
77 the dictionary.
78
79 The introduction in 2.4 of those methods was a mistake for the same reason:
80 code that previously saw all (urllib2 user)-provided headers in .headers
81 now sees only a subset (and the function interface is ugly and incomplete).
82 A better change would have been to replace .headers dict with a dict
83 subclass (or UserDict.DictMixin instance?) that preserved the .headers
84 interface and also provided access to the "unredirected" headers. It's
85 probably too late to fix that, though.
86
87
88 Check .capitalize() case normalization:
89
90 >>> url = "http://example.com"
91 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
92 'blah'
93 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
94 'blah'
95
96 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
97 but that could be changed in future.
98
99 """
100
101def test_request_headers_methods():
102 """
103 Note the case normalization of header names here, to .capitalize()-case.
104 This should be preserved for backwards-compatibility. (In the HTTP case,
105 normalization to .title()-case is done by urllib2 before sending headers to
Georg Brandl24420152008-05-26 16:32:26 +0000106 http.client).
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000107
108 >>> url = "http://example.com"
109 >>> r = Request(url, headers={"Spam-eggs": "blah"})
110 >>> r.has_header("Spam-eggs")
111 True
112 >>> r.header_items()
113 [('Spam-eggs', 'blah')]
114 >>> r.add_header("Foo-Bar", "baz")
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000115 >>> items = sorted(r.header_items())
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000116 >>> items
117 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
118
119 Note that e.g. r.has_header("spam-EggS") is currently False, and
120 r.get_header("spam-EggS") returns None, but that could be changed in
121 future.
122
123 >>> r.has_header("Not-there")
124 False
Guido van Rossum7131f842007-02-09 20:13:25 +0000125 >>> print(r.get_header("Not-there"))
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000126 None
127 >>> r.get_header("Not-there", "default")
128 'default'
129
130 """
131
132
Thomas Wouters477c8d52006-05-27 19:21:47 +0000133def test_password_manager(self):
134 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000135 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000136 >>> add = mgr.add_password
137 >>> add("Some Realm", "http://example.com/", "joe", "password")
138 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
139 >>> add("c", "http://example.com/foo", "foo", "ni")
140 >>> add("c", "http://example.com/bar", "bar", "nini")
141 >>> add("b", "http://example.com/", "first", "blah")
142 >>> add("b", "http://example.com/", "second", "spam")
143 >>> add("a", "http://example.com", "1", "a")
144 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
145 >>> add("Some Realm", "d.example.com", "4", "d")
146 >>> add("Some Realm", "e.example.com:3128", "5", "e")
147
148 >>> mgr.find_user_password("Some Realm", "example.com")
149 ('joe', 'password')
150 >>> mgr.find_user_password("Some Realm", "http://example.com")
151 ('joe', 'password')
152 >>> mgr.find_user_password("Some Realm", "http://example.com/")
153 ('joe', 'password')
154 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
155 ('joe', 'password')
156 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
157 ('joe', 'password')
158 >>> mgr.find_user_password("c", "http://example.com/foo")
159 ('foo', 'ni')
160 >>> mgr.find_user_password("c", "http://example.com/bar")
161 ('bar', 'nini')
162
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000163 Actually, this is really undefined ATM
164## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000165
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000166## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
167## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000168
169 Use latest add_password() in case of conflict:
170
171 >>> mgr.find_user_password("b", "http://example.com/")
172 ('second', 'spam')
173
174 No special relationship between a.example.com and example.com:
175
176 >>> mgr.find_user_password("a", "http://example.com/")
177 ('1', 'a')
178 >>> mgr.find_user_password("a", "http://a.example.com/")
179 (None, None)
180
181 Ports:
182
183 >>> mgr.find_user_password("Some Realm", "c.example.com")
184 (None, None)
185 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
186 ('3', 'c')
187 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
188 ('3', 'c')
189 >>> mgr.find_user_password("Some Realm", "d.example.com")
190 ('4', 'd')
191 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
192 ('5', 'e')
193
194 """
195 pass
196
197
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000198def test_password_manager_default_port(self):
199 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000200 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000201 >>> add = mgr.add_password
202
203 The point to note here is that we can't guess the default port if there's
204 no scheme. This applies to both add_password and find_user_password.
205
206 >>> add("f", "http://g.example.com:80", "10", "j")
207 >>> add("g", "http://h.example.com", "11", "k")
208 >>> add("h", "i.example.com:80", "12", "l")
209 >>> add("i", "j.example.com", "13", "m")
210 >>> mgr.find_user_password("f", "g.example.com:100")
211 (None, None)
212 >>> mgr.find_user_password("f", "g.example.com:80")
213 ('10', 'j')
214 >>> mgr.find_user_password("f", "g.example.com")
215 (None, None)
216 >>> mgr.find_user_password("f", "http://g.example.com:100")
217 (None, None)
218 >>> mgr.find_user_password("f", "http://g.example.com:80")
219 ('10', 'j')
220 >>> mgr.find_user_password("f", "http://g.example.com")
221 ('10', 'j')
222 >>> mgr.find_user_password("g", "h.example.com")
223 ('11', 'k')
224 >>> mgr.find_user_password("g", "h.example.com:80")
225 ('11', 'k')
226 >>> mgr.find_user_password("g", "http://h.example.com:80")
227 ('11', 'k')
228 >>> mgr.find_user_password("h", "i.example.com")
229 (None, None)
230 >>> mgr.find_user_password("h", "i.example.com:80")
231 ('12', 'l')
232 >>> mgr.find_user_password("h", "http://i.example.com:80")
233 ('12', 'l')
234 >>> mgr.find_user_password("i", "j.example.com")
235 ('13', 'm')
236 >>> mgr.find_user_password("i", "j.example.com:80")
237 (None, None)
238 >>> mgr.find_user_password("i", "http://j.example.com")
239 ('13', 'm')
240 >>> mgr.find_user_password("i", "http://j.example.com:80")
241 (None, None)
242
243 """
244
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000245class MockOpener:
246 addheaders = []
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000247 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
248 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000249 def error(self, proto, *args):
250 self.proto, self.args = proto, args
251
252class MockFile:
253 def read(self, count=None): pass
254 def readline(self, count=None): pass
255 def close(self): pass
256
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000257class MockHeaders(dict):
258 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000259 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000260
Guido van Rossum34d19282007-08-09 01:03:29 +0000261class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000262 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000263 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000264 self.code, self.msg, self.headers, self.url = code, msg, headers, url
265 def info(self):
266 return self.headers
267 def geturl(self):
268 return self.url
269
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000270class MockCookieJar:
271 def add_cookie_header(self, request):
272 self.ach_req = request
273 def extract_cookies(self, response, request):
274 self.ec_req, self.ec_r = request, response
275
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000276class FakeMethod:
277 def __init__(self, meth_name, action, handle):
278 self.meth_name = meth_name
279 self.handle = handle
280 self.action = action
281 def __call__(self, *args):
282 return self.handle(self.meth_name, self.action, *args)
283
Senthil Kumaran47fff872009-12-20 07:10:31 +0000284class MockHTTPResponse(io.IOBase):
285 def __init__(self, fp, msg, status, reason):
286 self.fp = fp
287 self.msg = msg
288 self.status = status
289 self.reason = reason
290 self.code = 200
291
292 def read(self):
293 return ''
294
295 def info(self):
296 return {}
297
298 def geturl(self):
299 return self.url
300
301
302class MockHTTPClass:
303 def __init__(self):
304 self.level = 0
305 self.req_headers = []
306 self.data = None
307 self.raise_on_endheaders = False
308 self._tunnel_headers = {}
309
310 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
311 self.host = host
312 self.timeout = timeout
313 return self
314
315 def set_debuglevel(self, level):
316 self.level = level
317
318 def set_tunnel(self, host, port=None, headers=None):
319 self._tunnel_host = host
320 self._tunnel_port = port
321 if headers:
322 self._tunnel_headers = headers
323 else:
324 self._tunnel_headers.clear()
325
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000326 def request(self, method, url, body=None, headers=None):
Senthil Kumaran47fff872009-12-20 07:10:31 +0000327 self.method = method
328 self.selector = url
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000329 if headers is not None:
330 self.req_headers += headers.items()
Senthil Kumaran47fff872009-12-20 07:10:31 +0000331 self.req_headers.sort()
332 if body:
333 self.data = body
334 if self.raise_on_endheaders:
335 import socket
336 raise socket.error()
337 def getresponse(self):
338 return MockHTTPResponse(MockFile(), {}, 200, "OK")
339
Victor Stinnera4c45d72011-06-17 14:01:18 +0200340 def close(self):
341 pass
342
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000343class MockHandler:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000344 # useful for testing handler machinery
345 # see add_ordered_mock_handlers() docstring
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000346 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000347 def __init__(self, methods):
348 self._define_methods(methods)
349 def _define_methods(self, methods):
350 for spec in methods:
351 if len(spec) == 2: name, action = spec
352 else: name, action = spec, None
353 meth = FakeMethod(name, action, self.handle)
354 setattr(self.__class__, name, meth)
355 def handle(self, fn_name, action, *args, **kwds):
356 self.parent.calls.append((self, fn_name, args, kwds))
357 if action is None:
358 return None
359 elif action == "return self":
360 return self
361 elif action == "return response":
362 res = MockResponse(200, "OK", {}, "")
363 return res
364 elif action == "return request":
365 return Request("http://blah/")
366 elif action.startswith("error"):
367 code = action[action.rfind(" ")+1:]
368 try:
369 code = int(code)
370 except ValueError:
371 pass
372 res = MockResponse(200, "OK", {}, "")
373 return self.parent.error("http", args[0], res, code, "", {})
374 elif action == "raise":
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000375 raise urllib.error.URLError("blah")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000376 assert False
377 def close(self): pass
378 def add_parent(self, parent):
379 self.parent = parent
380 self.parent.calls = []
381 def __lt__(self, other):
382 if not hasattr(other, "handler_order"):
383 # No handler_order, leave in original order. Yuck.
384 return True
385 return self.handler_order < other.handler_order
386
387def add_ordered_mock_handlers(opener, meth_spec):
388 """Create MockHandlers and add them to an OpenerDirector.
389
390 meth_spec: list of lists of tuples and strings defining methods to define
391 on handlers. eg:
392
393 [["http_error", "ftp_open"], ["http_open"]]
394
395 defines methods .http_error() and .ftp_open() on one handler, and
396 .http_open() on another. These methods just record their arguments and
397 return None. Using a tuple instead of a string causes the method to
398 perform some action (see MockHandler.handle()), eg:
399
400 [["http_error"], [("http_open", "return request")]]
401
402 defines .http_error() on one handler (which simply returns None), and
403 .http_open() on another handler, which returns a Request object.
404
405 """
406 handlers = []
407 count = 0
408 for meths in meth_spec:
409 class MockHandlerSubclass(MockHandler): pass
410 h = MockHandlerSubclass(meths)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000411 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000412 h.add_parent(opener)
413 count = count + 1
414 handlers.append(h)
415 opener.add_handler(h)
416 return handlers
417
Thomas Wouters477c8d52006-05-27 19:21:47 +0000418def build_test_opener(*handler_instances):
419 opener = OpenerDirector()
420 for h in handler_instances:
421 opener.add_handler(h)
422 return opener
423
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000424class MockHTTPHandler(urllib.request.BaseHandler):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000425 # useful for testing redirections and auth
426 # sends supplied headers and code as first response
427 # sends 200 OK as second response
428 def __init__(self, code, headers):
429 self.code = code
430 self.headers = headers
431 self.reset()
432 def reset(self):
433 self._count = 0
434 self.requests = []
435 def http_open(self, req):
Barry Warsaw820c1202008-06-12 04:06:45 +0000436 import email, http.client, copy
Guido van Rossum34d19282007-08-09 01:03:29 +0000437 from io import StringIO
Thomas Wouters477c8d52006-05-27 19:21:47 +0000438 self.requests.append(copy.deepcopy(req))
439 if self._count == 0:
440 self._count = self._count + 1
Georg Brandl24420152008-05-26 16:32:26 +0000441 name = http.client.responses[self.code]
Barry Warsaw820c1202008-06-12 04:06:45 +0000442 msg = email.message_from_string(self.headers)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000443 return self.parent.error(
444 "http", req, MockFile(), self.code, name, msg)
445 else:
446 self.req = req
Barry Warsaw820c1202008-06-12 04:06:45 +0000447 msg = email.message_from_string("\r\n\r\n")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000448 return MockResponse(200, "OK", msg, "", req.get_full_url())
449
Senthil Kumaran47fff872009-12-20 07:10:31 +0000450class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
451 # Useful for testing the Proxy-Authorization request by verifying the
452 # properties of httpcon
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000453
454 def __init__(self):
455 urllib.request.AbstractHTTPHandler.__init__(self)
456 self.httpconn = MockHTTPClass()
457
Senthil Kumaran47fff872009-12-20 07:10:31 +0000458 def https_open(self, req):
459 return self.do_open(self.httpconn, req)
460
Thomas Wouters477c8d52006-05-27 19:21:47 +0000461class MockPasswordManager:
462 def add_password(self, realm, uri, user, password):
463 self.realm = realm
464 self.url = uri
465 self.user = user
466 self.password = password
467 def find_user_password(self, realm, authuri):
468 self.target_realm = realm
469 self.target_url = authuri
470 return self.user, self.password
471
472
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000473class OpenerDirectorTests(unittest.TestCase):
474
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000475 def test_add_non_handler(self):
476 class NonHandler(object):
477 pass
478 self.assertRaises(TypeError,
479 OpenerDirector().add_handler, NonHandler())
480
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000481 def test_badly_named_methods(self):
482 # test work-around for three methods that accidentally follow the
483 # naming conventions for handler methods
484 # (*_open() / *_request() / *_response())
485
486 # These used to call the accidentally-named methods, causing a
487 # TypeError in real code; here, returning self from these mock
488 # methods would either cause no exception, or AttributeError.
489
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000490 from urllib.error import URLError
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000491
492 o = OpenerDirector()
493 meth_spec = [
494 [("do_open", "return self"), ("proxy_open", "return self")],
495 [("redirect_request", "return self")],
496 ]
497 handlers = add_ordered_mock_handlers(o, meth_spec)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000498 o.add_handler(urllib.request.UnknownHandler())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000499 for scheme in "do", "proxy", "redirect":
500 self.assertRaises(URLError, o.open, scheme+"://example.com/")
501
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000502 def test_handled(self):
503 # handler returning non-None means no more handlers will be called
504 o = OpenerDirector()
505 meth_spec = [
506 ["http_open", "ftp_open", "http_error_302"],
507 ["ftp_open"],
508 [("http_open", "return self")],
509 [("http_open", "return self")],
510 ]
511 handlers = add_ordered_mock_handlers(o, meth_spec)
512
513 req = Request("http://example.com/")
514 r = o.open(req)
515 # Second .http_open() gets called, third doesn't, since second returned
516 # non-None. Handlers without .http_open() never get any methods called
517 # on them.
518 # In fact, second mock handler defining .http_open() returns self
519 # (instead of response), which becomes the OpenerDirector's return
520 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000521 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000522 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
523 for expected, got in zip(calls, o.calls):
524 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000525 self.assertEqual((handler, name), expected)
526 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000527
528 def test_handler_order(self):
529 o = OpenerDirector()
530 handlers = []
531 for meths, handler_order in [
532 ([("http_open", "return self")], 500),
533 (["http_open"], 0),
534 ]:
535 class MockHandlerSubclass(MockHandler): pass
536 h = MockHandlerSubclass(meths)
537 h.handler_order = handler_order
538 handlers.append(h)
539 o.add_handler(h)
540
541 r = o.open("http://example.com/")
542 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000543 self.assertEqual(o.calls[0][0], handlers[1])
544 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000545
546 def test_raise(self):
547 # raising URLError stops processing of request
548 o = OpenerDirector()
549 meth_spec = [
550 [("http_open", "raise")],
551 [("http_open", "return self")],
552 ]
553 handlers = add_ordered_mock_handlers(o, meth_spec)
554
555 req = Request("http://example.com/")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000556 self.assertRaises(urllib.error.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000557 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000558
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000559 def test_http_error(self):
560 # XXX http_error_default
561 # http errors are a special case
562 o = OpenerDirector()
563 meth_spec = [
564 [("http_open", "error 302")],
565 [("http_error_400", "raise"), "http_open"],
566 [("http_error_302", "return response"), "http_error_303",
567 "http_error"],
568 [("http_error_302")],
569 ]
570 handlers = add_ordered_mock_handlers(o, meth_spec)
571
572 class Unknown:
573 def __eq__(self, other): return True
574
575 req = Request("http://example.com/")
576 r = o.open(req)
577 assert len(o.calls) == 2
578 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000579 (handlers[2], "http_error_302",
580 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000581 for expected, got in zip(calls, o.calls):
582 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000583 self.assertEqual((handler, method_name), got[:2])
584 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000585
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700586
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000587 def test_processors(self):
588 # *_request / *_response methods get called appropriately
589 o = OpenerDirector()
590 meth_spec = [
591 [("http_request", "return request"),
592 ("http_response", "return response")],
593 [("http_request", "return request"),
594 ("http_response", "return response")],
595 ]
596 handlers = add_ordered_mock_handlers(o, meth_spec)
597
598 req = Request("http://example.com/")
599 r = o.open(req)
600 # processor methods are called on *all* handlers that define them,
601 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000602 calls = [
603 (handlers[0], "http_request"), (handlers[1], "http_request"),
604 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000605
606 for i, (handler, name, args, kwds) in enumerate(o.calls):
607 if i < 2:
608 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000609 self.assertEqual((handler, name), calls[i])
610 self.assertEqual(len(args), 1)
Ezio Melottie9615932010-01-24 19:26:24 +0000611 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000612 else:
613 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000614 self.assertEqual((handler, name), calls[i])
615 self.assertEqual(len(args), 2)
Ezio Melottie9615932010-01-24 19:26:24 +0000616 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000617 # response from opener.open is None, because there's no
618 # handler that defines http_open to handle it
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000619 self.assertTrue(args[1] is None or
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000620 isinstance(args[1], MockResponse))
621
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700622 def test_method_deprecations(self):
623 req = Request("http://www.example.com")
Senthil Kumaran08bd4aa2012-04-11 23:05:49 +0800624
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800625 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700626 req.add_data("data")
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800627 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700628 req.get_data()
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800629 with self.assertWarns(DeprecationWarning):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -0700630 req.has_data()
631 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700632 req.get_host()
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800633 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700634 req.get_selector()
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800635 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700636 req.is_unverifiable()
Senthil Kumaran80a133b2012-04-12 19:28:07 +0800637 with self.assertWarns(DeprecationWarning):
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700638 req.get_origin_req_host()
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -0700639 with self.assertWarns(DeprecationWarning):
640 req.get_type()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000641
Senthil Kumaran08bd4aa2012-04-11 23:05:49 +0800642
Tim Peters58eb11c2004-01-18 20:29:55 +0000643def sanepathname2url(path):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000644 try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +0000645 path.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +0000646 except UnicodeEncodeError:
647 raise unittest.SkipTest("path is not encodable to utf8")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000648 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000649 if os.name == "nt" and urlpath.startswith("///"):
650 urlpath = urlpath[2:]
651 # XXX don't ask me about the mac...
652 return urlpath
653
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000654class HandlerTests(unittest.TestCase):
655
656 def test_ftp(self):
657 class MockFTPWrapper:
658 def __init__(self, data): self.data = data
659 def retrfile(self, filename, filetype):
660 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000661 return io.StringIO(self.data), len(self.data)
Nadeem Vawda08f5f7a2011-07-23 14:03:00 +0200662 def close(self): pass
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000663
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000664 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000665 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000666 def connect_ftp(self, user, passwd, host, port, dirs,
667 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000668 self.user, self.passwd = user, passwd
669 self.host, self.port = host, port
670 self.dirs = dirs
671 self.ftpwrapper = MockFTPWrapper(self.data)
672 return self.ftpwrapper
673
Georg Brandlf78e02b2008-06-10 17:40:04 +0000674 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000675 data = "rheum rhaponicum"
676 h = NullFTPHandler(data)
677 o = h.parent = MockOpener()
678
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000679 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000680 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000681 "localhost", ftplib.FTP_PORT, "", "", "I",
682 ["foo", "bar"], "baz.html", "text/html"),
683 ("ftp://parrot@localhost/foo/bar/baz.html",
684 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
685 ["foo", "bar"], "baz.html", "text/html"),
686 ("ftp://%25parrot@localhost/foo/bar/baz.html",
687 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
688 ["foo", "bar"], "baz.html", "text/html"),
689 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
690 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000691 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000692 ("ftp://localhost:80/foo/bar/",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000693 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000694 ["foo", "bar"], "", None),
695 ("ftp://localhost/baz.gif;type=a",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000696 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000697 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000698 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000699 req = Request(url)
700 req.timeout = None
701 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000702 # ftp authentication not yet implemented by FTPHandler
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000703 self.assertEqual(h.user, user)
704 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000705 self.assertEqual(h.host, socket.gethostbyname(host))
706 self.assertEqual(h.port, port)
707 self.assertEqual(h.dirs, dirs)
708 self.assertEqual(h.ftpwrapper.filename, filename)
709 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000710 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000711 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000712 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000713
714 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000715 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000716 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000717 o = h.parent = MockOpener()
718
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000719 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000720 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000721 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000722 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000723 "file://localhost%s" % urlpath,
724 "file://%s" % urlpath,
725 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000726 ]
727 try:
728 localaddr = socket.gethostbyname(socket.gethostname())
729 except socket.gaierror:
730 localaddr = ''
731 if localaddr:
732 urls.append("file://%s%s" % (localaddr, urlpath))
733
734 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000735 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000736 try:
737 try:
738 f.write(towrite)
739 finally:
740 f.close()
741
742 r = h.file_open(Request(url))
743 try:
744 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000745 headers = r.info()
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000746 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000747 finally:
748 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000749 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000750 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000751 finally:
752 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000753 self.assertEqual(data, towrite)
754 self.assertEqual(headers["Content-type"], "text/plain")
755 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000756 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000757 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000758
759 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000760 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000761 "file:///file_does_not_exist.txt",
762 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
763 os.getcwd(), TESTFN),
764 "file://somerandomhost.ontheinternet.com%s/%s" %
765 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000766 ]:
767 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000768 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000769 try:
770 f.write(towrite)
771 finally:
772 f.close()
773
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000774 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000775 h.file_open, Request(url))
776 finally:
777 os.remove(TESTFN)
778
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000779 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000780 o = h.parent = MockOpener()
781 # XXXX why does // mean ftp (and /// mean not ftp!), and where
782 # is file: scheme specified? I think this is really a bug, and
783 # what was intended was to distinguish between URLs like:
784 # file:/blah.txt (a file)
785 # file://localhost/blah.txt (a file)
786 # file:///blah.txt (a file)
787 # file://ftp.example.com/blah.txt (an ftp URL)
788 for url, ftp in [
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000789 ("file://ftp.example.com//foo.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000790 ("file://ftp.example.com///foo.txt", False),
791# XXXX bug: fails with OSError, should be URLError
792 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000793 ("file://somehost//foo/something.txt", False),
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000794 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000795 ]:
796 req = Request(url)
797 try:
798 h.file_open(req)
799 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000800 except (urllib.error.URLError, OSError):
Florent Xicluna419e3842010-08-08 16:16:07 +0000801 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000802 else:
Florent Xicluna419e3842010-08-08 16:16:07 +0000803 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000804 self.assertEqual(req.type, "ftp")
Łukasz Langad7e81cc2011-01-09 18:18:53 +0000805 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000806
807 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000808
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000809 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000810 o = h.parent = MockOpener()
811
812 url = "http://example.com/"
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000813 for method, data in [("GET", None), ("POST", b"blah")]:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000814 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000815 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000816 req.add_unredirected_header("Spam", "eggs")
817 http = MockHTTPClass()
818 r = h.do_open(http, req)
819
820 # result attributes
821 r.read; r.readline # wrapped MockFile methods
822 r.info; r.geturl # addinfourl methods
823 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
824 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000825 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000826 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000827
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000828 self.assertEqual(http.host, "example.com")
829 self.assertEqual(http.level, 0)
830 self.assertEqual(http.method, method)
831 self.assertEqual(http.selector, "/")
832 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000833 [("Connection", "close"),
834 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000835 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000836
837 # check socket.error converted to URLError
838 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000839 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000840
Senthil Kumaran29333122011-02-11 11:25:47 +0000841 # Check for TypeError on POST data which is str.
842 req = Request("http://example.com/","badpost")
843 self.assertRaises(TypeError, h.do_request_, req)
844
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000845 # check adding of standard headers
846 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000847 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000848 req = Request("http://example.com/", data)
849 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000850 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000851 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000852 self.assertNotIn("Content-length", req.unredirected_hdrs)
853 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000854 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000855 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
856 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000857 "application/x-www-form-urlencoded")
858 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000859 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
860 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000861
862 # don't clobber existing headers
863 req.add_unredirected_header("Content-length", "foo")
864 req.add_unredirected_header("Content-type", "bar")
865 req.add_unredirected_header("Host", "baz")
866 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000867 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000868 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
869 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000870 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
871 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000872
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000873 # Check iterable body support
874 def iterable_body():
875 yield b"one"
876 yield b"two"
877 yield b"three"
878
879 for headers in {}, {"Content-Length": 11}:
880 req = Request("http://example.com/", iterable_body(), headers)
881 if not headers:
882 # Having an iterable body without a Content-Length should
883 # raise an exception
884 self.assertRaises(ValueError, h.do_request_, req)
885 else:
886 newreq = h.do_request_(req)
887
Senthil Kumaran29333122011-02-11 11:25:47 +0000888 # A file object.
889 # Test only Content-Length attribute of request.
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000890
Senthil Kumaran29333122011-02-11 11:25:47 +0000891 file_obj = io.BytesIO()
892 file_obj.write(b"Something\nSomething\nSomething\n")
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000893
894 for headers in {}, {"Content-Length": 30}:
895 req = Request("http://example.com/", file_obj, headers)
896 if not headers:
897 # Having an iterable body without a Content-Length should
898 # raise an exception
899 self.assertRaises(ValueError, h.do_request_, req)
900 else:
901 newreq = h.do_request_(req)
902 self.assertEqual(int(newreq.get_header('Content-length')),30)
903
904 file_obj.close()
905
906 # array.array Iterable - Content Length is calculated
907
908 iterable_array = array.array("I",[1,2,3,4])
909
910 for headers in {}, {"Content-Length": 16}:
911 req = Request("http://example.com/", iterable_array, headers)
912 newreq = h.do_request_(req)
913 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000914
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000915 def test_http_doubleslash(self):
916 # Checks the presence of any unnecessary double slash in url does not
917 # break anything. Previously, a double slash directly after the host
Ezio Melottie130a522011-10-19 10:58:56 +0300918 # could cause incorrect parsing.
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000919 h = urllib.request.AbstractHTTPHandler()
920 o = h.parent = MockOpener()
921
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000922 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000923 ds_urls = [
924 "http://example.com/foo/bar/baz.html",
925 "http://example.com//foo/bar/baz.html",
926 "http://example.com/foo//bar/baz.html",
927 "http://example.com/foo/bar//baz.html"
928 ]
929
930 for ds_url in ds_urls:
931 ds_req = Request(ds_url, data)
932
933 # Check whether host is determined correctly if there is no proxy
934 np_ds_req = h.do_request_(ds_req)
935 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
936
937 # Check whether host is determined correctly if there is a proxy
938 ds_req.set_proxy("someproxy:3128",None)
939 p_ds_req = h.do_request_(ds_req)
940 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
941
Senthil Kumaranc2958622010-11-22 04:48:26 +0000942 def test_fixpath_in_weirdurls(self):
943 # Issue4493: urllib2 to supply '/' when to urls where path does not
944 # start with'/'
945
946 h = urllib.request.AbstractHTTPHandler()
947 o = h.parent = MockOpener()
948
949 weird_url = 'http://www.python.org?getspam'
950 req = Request(weird_url)
951 newreq = h.do_request_(req)
952 self.assertEqual(newreq.host,'www.python.org')
953 self.assertEqual(newreq.selector,'/?getspam')
954
955 url_without_path = 'http://www.python.org'
956 req = Request(url_without_path)
957 newreq = h.do_request_(req)
958 self.assertEqual(newreq.host,'www.python.org')
959 self.assertEqual(newreq.selector,'')
960
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000961
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000962 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000963 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000964 o = h.parent = MockOpener()
965
966 url = "http://example.com/"
967 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000968 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000969 r = MockResponse(200, "OK", {}, "", url)
970 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000971 self.assertIs(r, newr)
972 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000973 r = MockResponse(202, "Accepted", {}, "", url)
974 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000975 self.assertIs(r, newr)
976 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000977 r = MockResponse(206, "Partial content", {}, "", url)
978 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000979 self.assertIs(r, newr)
980 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000981 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000982 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000983 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000984 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000985 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000986
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000987 def test_cookies(self):
988 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000989 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000990 o = h.parent = MockOpener()
991
992 req = Request("http://example.com/")
993 r = MockResponse(200, "OK", {}, "")
994 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000995 self.assertIs(cj.ach_req, req)
996 self.assertIs(cj.ach_req, newreq)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -0700997 self.assertEqual(req.origin_req_host, "example.com")
998 self.assertFalse(req.unverifiable)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000999 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +00001000 self.assertIs(cj.ec_req, req)
1001 self.assertIs(cj.ec_r, r)
1002 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001003
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001004 def test_redirect(self):
1005 from_url = "http://example.com/a.html"
1006 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001007 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001008 o = h.parent = MockOpener()
1009
1010 # ordinary redirect behaviour
1011 for code in 301, 302, 303, 307:
1012 for data in None, "blah\nblah\n":
1013 method = getattr(h, "http_error_%s" % code)
1014 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001015 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001016 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +00001017 if data is not None:
1018 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001019 req.add_unredirected_header("Spam", "spam")
1020 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001021 method(req, MockFile(), code, "Blah",
1022 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001023 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001024 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001025 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001026 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001027 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001028 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001029 except AttributeError:
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001030 self.assertFalse(o.req.data)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001031
1032 # now it's a GET, there should not be headers regarding content
1033 # (possibly dragged from before being a POST)
1034 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +00001035 self.assertNotIn("content-length", headers)
1036 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001037
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001038 self.assertEqual(o.req.headers["Nonsense"],
1039 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001040 self.assertNotIn("Spam", o.req.headers)
1041 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001042
1043 # loop detection
1044 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001045 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001046 def redirect(h, req, url=to_url):
1047 h.http_error_302(req, MockFile(), 302, "Blah",
1048 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001049 # Note that the *original* request shares the same record of
1050 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001051
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001052 # detect infinite loop redirect of a URL to itself
1053 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001054 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001055 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001056 try:
1057 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001058 redirect(h, req, "http://example.com/")
1059 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001060 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001061 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001062 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001063
1064 # detect endless non-repeating chain of redirects
1065 req = Request(from_url, origin_req_host="example.com")
1066 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001067 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001068 try:
1069 while 1:
1070 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001071 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001072 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001073 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001074 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001075
guido@google.coma119df92011-03-29 11:41:02 -07001076
1077 def test_invalid_redirect(self):
1078 from_url = "http://example.com/a.html"
1079 valid_schemes = ['http','https','ftp']
1080 invalid_schemes = ['file','imap','ldap']
1081 schemeless_url = "example.com/b.html"
1082 h = urllib.request.HTTPRedirectHandler()
1083 o = h.parent = MockOpener()
1084 req = Request(from_url)
1085 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1086
1087 for scheme in invalid_schemes:
1088 invalid_url = scheme + '://' + schemeless_url
1089 self.assertRaises(urllib.error.HTTPError, h.http_error_302,
1090 req, MockFile(), 302, "Security Loophole",
1091 MockHeaders({"location": invalid_url}))
1092
1093 for scheme in valid_schemes:
1094 valid_url = scheme + '://' + schemeless_url
1095 h.http_error_302(req, MockFile(), 302, "That's fine",
1096 MockHeaders({"location": valid_url}))
1097 self.assertEqual(o.req.get_full_url(), valid_url)
1098
Senthil Kumaran6497aa32012-01-04 13:46:59 +08001099 def test_relative_redirect(self):
1100 from_url = "http://example.com/a.html"
1101 relative_url = "/b.html"
1102 h = urllib.request.HTTPRedirectHandler()
1103 o = h.parent = MockOpener()
1104 req = Request(from_url)
1105 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1106
1107 valid_url = urllib.parse.urljoin(from_url,relative_url)
1108 h.http_error_302(req, MockFile(), 302, "That's fine",
1109 MockHeaders({"location": valid_url}))
1110 self.assertEqual(o.req.get_full_url(), valid_url)
1111
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001112 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001113 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001114 from http.cookiejar import CookieJar
1115 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001116
1117 cj = CookieJar()
1118 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001119 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001120 hdeh = urllib.request.HTTPDefaultErrorHandler()
1121 hrh = urllib.request.HTTPRedirectHandler()
1122 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001123 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001124 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001125 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001126
Senthil Kumaran26430412011-04-13 07:01:19 +08001127 def test_redirect_fragment(self):
1128 redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
1129 hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
1130 hdeh = urllib.request.HTTPDefaultErrorHandler()
1131 hrh = urllib.request.HTTPRedirectHandler()
1132 o = build_test_opener(hh, hdeh, hrh)
1133 fp = o.open('http://www.example.com')
1134 self.assertEqual(fp.geturl(), redirected_url.strip())
1135
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001136 def test_proxy(self):
1137 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001138 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001139 o.add_handler(ph)
1140 meth_spec = [
1141 [("http_open", "return response")]
1142 ]
1143 handlers = add_ordered_mock_handlers(o, meth_spec)
1144
1145 req = Request("http://acme.example.com/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001146 self.assertEqual(req.host, "acme.example.com")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001147 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001148 self.assertEqual(req.host, "proxy.example.com:3128")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001149
1150 self.assertEqual([(handlers[0], "http_open")],
1151 [tup[0:2] for tup in o.calls])
1152
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001153 def test_proxy_no_proxy(self):
1154 os.environ['no_proxy'] = 'python.org'
1155 o = OpenerDirector()
1156 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1157 o.add_handler(ph)
1158 req = Request("http://www.perl.org/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001159 self.assertEqual(req.host, "www.perl.org")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001160 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001161 self.assertEqual(req.host, "proxy.example.com")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001162 req = Request("http://www.python.org")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001163 self.assertEqual(req.host, "www.python.org")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001164 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001165 self.assertEqual(req.host, "www.python.org")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001166 del os.environ['no_proxy']
1167
Ronald Oussorene72e1612011-03-14 18:15:25 -04001168 def test_proxy_no_proxy_all(self):
1169 os.environ['no_proxy'] = '*'
1170 o = OpenerDirector()
1171 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1172 o.add_handler(ph)
1173 req = Request("http://www.python.org")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001174 self.assertEqual(req.host, "www.python.org")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001175 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001176 self.assertEqual(req.host, "www.python.org")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001177 del os.environ['no_proxy']
1178
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001179
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001180 def test_proxy_https(self):
1181 o = OpenerDirector()
1182 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1183 o.add_handler(ph)
1184 meth_spec = [
1185 [("https_open", "return response")]
1186 ]
1187 handlers = add_ordered_mock_handlers(o, meth_spec)
1188
1189 req = Request("https://www.example.com/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001190 self.assertEqual(req.host, "www.example.com")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001191 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001192 self.assertEqual(req.host, "proxy.example.com:3128")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001193 self.assertEqual([(handlers[0], "https_open")],
1194 [tup[0:2] for tup in o.calls])
1195
Senthil Kumaran47fff872009-12-20 07:10:31 +00001196 def test_proxy_https_proxy_authorization(self):
1197 o = OpenerDirector()
1198 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1199 o.add_handler(ph)
1200 https_handler = MockHTTPSHandler()
1201 o.add_handler(https_handler)
1202 req = Request("https://www.example.com/")
1203 req.add_header("Proxy-Authorization","FooBar")
1204 req.add_header("User-Agent","Grail")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001205 self.assertEqual(req.host, "www.example.com")
Senthil Kumaran47fff872009-12-20 07:10:31 +00001206 self.assertIsNone(req._tunnel_host)
1207 r = o.open(req)
1208 # Verify Proxy-Authorization gets tunneled to request.
1209 # httpsconn req_headers do not have the Proxy-Authorization header but
1210 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001211 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001212 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001213 self.assertIn(("User-Agent","Grail"),
1214 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001215 self.assertIsNotNone(req._tunnel_host)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001216 self.assertEqual(req.host, "proxy.example.com:3128")
Senthil Kumaran47fff872009-12-20 07:10:31 +00001217 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001218
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001219 # TODO: This should be only for OSX
1220 @unittest.skipUnless(sys.platform == 'darwin', "only relevant for OSX")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001221 def test_osx_proxy_bypass(self):
1222 bypass = {
1223 'exclude_simple': False,
1224 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1225 '10.0/16']
1226 }
1227 # Check hosts that should trigger the proxy bypass
1228 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1229 '10.0.0.1'):
1230 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1231 'expected bypass of %s to be True' % host)
1232 # Check hosts that should not trigger the proxy bypass
1233 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1234 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1235 'expected bypass of %s to be False' % host)
1236
1237 # Check the exclude_simple flag
1238 bypass = {'exclude_simple': True, 'exceptions': []}
1239 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1240
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001241 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001242 opener = OpenerDirector()
1243 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001244 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001245 realm = "ACME Widget Store"
1246 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001247 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1248 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001249 opener.add_handler(auth_handler)
1250 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001251 self._test_basic_auth(opener, auth_handler, "Authorization",
1252 realm, http_handler, password_manager,
1253 "http://acme.example.com/protected",
1254 "http://acme.example.com/protected",
1255 )
1256
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001257 def test_basic_auth_with_single_quoted_realm(self):
1258 self.test_basic_auth(quote_char="'")
1259
Senthil Kumaran34f3fcc2012-05-15 22:30:25 +08001260 def test_basic_auth_with_unquoted_realm(self):
1261 opener = OpenerDirector()
1262 password_manager = MockPasswordManager()
1263 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
1264 realm = "ACME Widget Store"
1265 http_handler = MockHTTPHandler(
1266 401, 'WWW-Authenticate: Basic realm=%s\r\n\r\n' % realm)
1267 opener.add_handler(auth_handler)
1268 opener.add_handler(http_handler)
Senthil Kumaran0ea91cb2012-05-15 23:59:42 +08001269 with self.assertWarns(UserWarning):
1270 self._test_basic_auth(opener, auth_handler, "Authorization",
1271 realm, http_handler, password_manager,
1272 "http://acme.example.com/protected",
1273 "http://acme.example.com/protected",
1274 )
Senthil Kumaran34f3fcc2012-05-15 22:30:25 +08001275
Thomas Wouters477c8d52006-05-27 19:21:47 +00001276 def test_proxy_basic_auth(self):
1277 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001278 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001279 opener.add_handler(ph)
1280 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001281 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001282 realm = "ACME Networks"
1283 http_handler = MockHTTPHandler(
1284 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001285 opener.add_handler(auth_handler)
1286 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001287 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001288 realm, http_handler, password_manager,
1289 "http://acme.example.com:3128/protected",
1290 "proxy.example.com:3128",
1291 )
1292
1293 def test_basic_and_digest_auth_handlers(self):
Andrew Svetlov7bd61cb2012-12-19 22:49:25 +02001294 # HTTPDigestAuthHandler raised an exception if it couldn't handle a 40*
Thomas Wouters477c8d52006-05-27 19:21:47 +00001295 # response (http://python.org/sf/1479302), where it should instead
1296 # return None to allow another handler (especially
1297 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001298
1299 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1300 # try digest first (since it's the strongest auth scheme), so we record
1301 # order of calls here to check digest comes first:
1302 class RecordingOpenerDirector(OpenerDirector):
1303 def __init__(self):
1304 OpenerDirector.__init__(self)
1305 self.recorded = []
1306 def record(self, info):
1307 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001308 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001309 def http_error_401(self, *args, **kwds):
1310 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001311 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001312 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001313 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001314 def http_error_401(self, *args, **kwds):
1315 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001316 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001317 *args, **kwds)
1318
1319 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001320 password_manager = MockPasswordManager()
1321 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001322 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001323 realm = "ACME Networks"
1324 http_handler = MockHTTPHandler(
1325 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001326 opener.add_handler(basic_handler)
1327 opener.add_handler(digest_handler)
1328 opener.add_handler(http_handler)
1329
1330 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001331 self._test_basic_auth(opener, basic_handler, "Authorization",
1332 realm, http_handler, password_manager,
1333 "http://acme.example.com/protected",
1334 "http://acme.example.com/protected",
1335 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001336 # check digest was tried before basic (twice, because
1337 # _test_basic_auth called .open() twice)
1338 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001339
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001340 def test_unsupported_auth_digest_handler(self):
1341 opener = OpenerDirector()
1342 # While using DigestAuthHandler
1343 digest_auth_handler = urllib.request.HTTPDigestAuthHandler(None)
1344 http_handler = MockHTTPHandler(
1345 401, 'WWW-Authenticate: Kerberos\r\n\r\n')
1346 opener.add_handler(digest_auth_handler)
1347 opener.add_handler(http_handler)
1348 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1349
1350 def test_unsupported_auth_basic_handler(self):
1351 # While using BasicAuthHandler
1352 opener = OpenerDirector()
1353 basic_auth_handler = urllib.request.HTTPBasicAuthHandler(None)
1354 http_handler = MockHTTPHandler(
1355 401, 'WWW-Authenticate: NTLM\r\n\r\n')
1356 opener.add_handler(basic_auth_handler)
1357 opener.add_handler(http_handler)
1358 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1359
Thomas Wouters477c8d52006-05-27 19:21:47 +00001360 def _test_basic_auth(self, opener, auth_handler, auth_header,
1361 realm, http_handler, password_manager,
1362 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001363 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001364 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001365
1366 # .add_password() fed through to password manager
1367 auth_handler.add_password(realm, request_url, user, password)
1368 self.assertEqual(realm, password_manager.realm)
1369 self.assertEqual(request_url, password_manager.url)
1370 self.assertEqual(user, password_manager.user)
1371 self.assertEqual(password, password_manager.password)
1372
1373 r = opener.open(request_url)
1374
1375 # should have asked the password manager for the username/password
1376 self.assertEqual(password_manager.target_realm, realm)
1377 self.assertEqual(password_manager.target_url, protected_url)
1378
1379 # expect one request without authorization, then one with
1380 self.assertEqual(len(http_handler.requests), 2)
1381 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001382 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001383 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001384 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001385 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1386 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001387 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1388 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001389 # if the password manager can't find a password, the handler won't
1390 # handle the HTTP auth error
1391 password_manager.user = password_manager.password = None
1392 http_handler.reset()
1393 r = opener.open(request_url)
1394 self.assertEqual(len(http_handler.requests), 1)
1395 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1396
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001397
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001398class MiscTests(unittest.TestCase):
1399
1400 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001401 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1402 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001403 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001404 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001405 def bar_open(self): pass
1406
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001407 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001408
1409 o = build_opener(FooHandler, BarHandler)
1410 self.opener_has_handler(o, FooHandler)
1411 self.opener_has_handler(o, BarHandler)
1412
1413 # can take a mix of classes and instances
1414 o = build_opener(FooHandler, BarHandler())
1415 self.opener_has_handler(o, FooHandler)
1416 self.opener_has_handler(o, BarHandler)
1417
1418 # subclasses of default handlers override default handlers
1419 o = build_opener(MyHTTPHandler)
1420 self.opener_has_handler(o, MyHTTPHandler)
1421
1422 # a particular case of overriding: default handlers can be passed
1423 # in explicitly
1424 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001425 self.opener_has_handler(o, urllib.request.HTTPHandler)
1426 o = build_opener(urllib.request.HTTPHandler)
1427 self.opener_has_handler(o, urllib.request.HTTPHandler)
1428 o = build_opener(urllib.request.HTTPHandler())
1429 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001430
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001431 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001432 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001433 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1434 self.opener_has_handler(o, MyHTTPHandler)
1435 self.opener_has_handler(o, MyOtherHTTPHandler)
1436
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001437 def opener_has_handler(self, opener, handler_class):
Florent Xicluna419e3842010-08-08 16:16:07 +00001438 self.assertTrue(any(h.__class__ == handler_class
1439 for h in opener.handlers))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001440
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001441class RequestTests(unittest.TestCase):
1442
1443 def setUp(self):
1444 self.get = Request("http://www.python.org/~jeremy/")
1445 self.post = Request("http://www.python.org/~jeremy/",
1446 "data",
1447 headers={"X-Test": "test"})
1448
1449 def test_method(self):
1450 self.assertEqual("POST", self.post.get_method())
1451 self.assertEqual("GET", self.get.get_method())
1452
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001453 def test_data(self):
1454 self.assertFalse(self.get.data)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001455 self.assertEqual("GET", self.get.get_method())
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001456 self.get.data = "spam"
1457 self.assertTrue(self.get.data)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001458 self.assertEqual("POST", self.get.get_method())
1459
1460 def test_get_full_url(self):
1461 self.assertEqual("http://www.python.org/~jeremy/",
1462 self.get.get_full_url())
1463
1464 def test_selector(self):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001465 self.assertEqual("/~jeremy/", self.get.selector)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001466 req = Request("http://www.python.org/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001467 self.assertEqual("/", req.selector)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001468
1469 def test_get_type(self):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001470 self.assertEqual("http", self.get.type)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001471
1472 def test_get_host(self):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001473 self.assertEqual("www.python.org", self.get.host)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001474
1475 def test_get_host_unquote(self):
1476 req = Request("http://www.%70ython.org/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001477 self.assertEqual("www.python.org", req.host)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001478
1479 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001480 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001481 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001482 self.assertTrue(self.get.has_proxy())
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001483 self.assertEqual("www.python.org", self.get.origin_req_host)
1484 self.assertEqual("www.perl.org", self.get.host)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001485
Senthil Kumarand95cc752010-08-08 11:27:53 +00001486 def test_wrapped_url(self):
1487 req = Request("<URL:http://www.python.org>")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001488 self.assertEqual("www.python.org", req.host)
Senthil Kumarand95cc752010-08-08 11:27:53 +00001489
Senthil Kumaran26430412011-04-13 07:01:19 +08001490 def test_url_fragment(self):
Senthil Kumarand95cc752010-08-08 11:27:53 +00001491 req = Request("http://www.python.org/?qs=query#fragment=true")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001492 self.assertEqual("/?qs=query", req.selector)
Senthil Kumarand95cc752010-08-08 11:27:53 +00001493 req = Request("http://www.python.org/#fun=true")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001494 self.assertEqual("/", req.selector)
Senthil Kumarand95cc752010-08-08 11:27:53 +00001495
Senthil Kumaran26430412011-04-13 07:01:19 +08001496 # Issue 11703: geturl() omits fragment in the original URL.
1497 url = 'http://docs.python.org/library/urllib2.html#OK'
1498 req = Request(url)
1499 self.assertEqual(req.get_full_url(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001500
Senthil Kumaran41e66a22012-12-23 09:04:24 -08001501 def test_HTTPError_interface(self):
1502 """
1503 Issue 13211 reveals that HTTPError didn't implement the URLError
1504 interface even though HTTPError is a subclass of URLError.
Jason R. Coombsaa204db2011-11-07 10:50:32 -05001505
Senthil Kumaran0a6b9ec2012-12-23 09:12:13 -08001506 >>> msg = 'something bad happened'
Senthil Kumaran2a4d2452013-03-19 16:11:07 -07001507 >>> url = code = fp = None
1508 >>> hdrs = 'Content-Length: 42'
Senthil Kumaran0a6b9ec2012-12-23 09:12:13 -08001509 >>> err = urllib.error.HTTPError(url, code, msg, hdrs, fp)
Senthil Kumaran41e66a22012-12-23 09:04:24 -08001510 >>> assert hasattr(err, 'reason')
1511 >>> err.reason
1512 'something bad happened'
Senthil Kumaran2a4d2452013-03-19 16:11:07 -07001513 >>> assert hasattr(err, 'hdrs')
1514 >>> err.hdrs
1515 'Content-Length: 42'
1516 >>> expected_errmsg = 'HTTP Error %s: %s' % (err.code, err.msg)
1517 >>> assert str(err) == expected_errmsg
Senthil Kumaran41e66a22012-12-23 09:04:24 -08001518 """
1519
1520 def test_HTTPError_interface_call(self):
1521 """
1522 Issue 15701 - HTTPError interface has info method available from URLError
1523 """
1524 err = urllib.request.HTTPError(msg="something bad happened", url=None,
1525 code=None, hdrs='Content-Length:42', fp=None)
1526 self.assertTrue(hasattr(err, 'reason'))
1527 assert hasattr(err, 'reason')
1528 assert hasattr(err, 'info')
1529 assert callable(err.info)
1530 try:
1531 err.info()
1532 except AttributeError:
1533 self.fail('err.info call failed.')
1534 self.assertEqual(err.info(), "Content-Length:42")
Jason R. Coombsaa204db2011-11-07 10:50:32 -05001535
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001536def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001537 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001538 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001539 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001540 tests = (TrivialTests,
1541 OpenerDirectorTests,
1542 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001543 MiscTests,
1544 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001545 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001546
1547if __name__ == "__main__":
1548 test_main(verbose=True)