blob: 0e0572383d32acc80c08afda2ab1c4ee4b8ef032 [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
Andrew Svetlovbff98fe2012-11-27 23:06:19 +0200130 Method r.remove_header should remove items both from r.headers and
131 r.unredirected_hdrs dictionaries
132
133 >>> r.remove_header("Spam-eggs")
134 >>> r.has_header("Spam-eggs")
135 False
136 >>> r.add_unredirected_header("Unredirected-spam", "Eggs")
137 >>> r.has_header("Unredirected-spam")
138 True
139 >>> r.remove_header("Unredirected-spam")
140 >>> r.has_header("Unredirected-spam")
141 False
142
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000143 """
144
145
Thomas Wouters477c8d52006-05-27 19:21:47 +0000146def test_password_manager(self):
147 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000148 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000149 >>> add = mgr.add_password
150 >>> add("Some Realm", "http://example.com/", "joe", "password")
151 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
152 >>> add("c", "http://example.com/foo", "foo", "ni")
153 >>> add("c", "http://example.com/bar", "bar", "nini")
154 >>> add("b", "http://example.com/", "first", "blah")
155 >>> add("b", "http://example.com/", "second", "spam")
156 >>> add("a", "http://example.com", "1", "a")
157 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
158 >>> add("Some Realm", "d.example.com", "4", "d")
159 >>> add("Some Realm", "e.example.com:3128", "5", "e")
160
161 >>> mgr.find_user_password("Some Realm", "example.com")
162 ('joe', 'password')
163 >>> mgr.find_user_password("Some Realm", "http://example.com")
164 ('joe', 'password')
165 >>> mgr.find_user_password("Some Realm", "http://example.com/")
166 ('joe', 'password')
167 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
168 ('joe', 'password')
169 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
170 ('joe', 'password')
171 >>> mgr.find_user_password("c", "http://example.com/foo")
172 ('foo', 'ni')
173 >>> mgr.find_user_password("c", "http://example.com/bar")
174 ('bar', 'nini')
175
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000176 Actually, this is really undefined ATM
177## Currently, we use the highest-level path where more than one match:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000178
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000179## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
180## ('joe', 'password')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000181
182 Use latest add_password() in case of conflict:
183
184 >>> mgr.find_user_password("b", "http://example.com/")
185 ('second', 'spam')
186
187 No special relationship between a.example.com and example.com:
188
189 >>> mgr.find_user_password("a", "http://example.com/")
190 ('1', 'a')
191 >>> mgr.find_user_password("a", "http://a.example.com/")
192 (None, None)
193
194 Ports:
195
196 >>> mgr.find_user_password("Some Realm", "c.example.com")
197 (None, None)
198 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
199 ('3', 'c')
200 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
201 ('3', 'c')
202 >>> mgr.find_user_password("Some Realm", "d.example.com")
203 ('4', 'd')
204 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
205 ('5', 'e')
206
207 """
208 pass
209
210
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000211def test_password_manager_default_port(self):
212 """
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000213 >>> mgr = urllib.request.HTTPPasswordMgr()
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000214 >>> add = mgr.add_password
215
216 The point to note here is that we can't guess the default port if there's
217 no scheme. This applies to both add_password and find_user_password.
218
219 >>> add("f", "http://g.example.com:80", "10", "j")
220 >>> add("g", "http://h.example.com", "11", "k")
221 >>> add("h", "i.example.com:80", "12", "l")
222 >>> add("i", "j.example.com", "13", "m")
223 >>> mgr.find_user_password("f", "g.example.com:100")
224 (None, None)
225 >>> mgr.find_user_password("f", "g.example.com:80")
226 ('10', 'j')
227 >>> mgr.find_user_password("f", "g.example.com")
228 (None, None)
229 >>> mgr.find_user_password("f", "http://g.example.com:100")
230 (None, None)
231 >>> mgr.find_user_password("f", "http://g.example.com:80")
232 ('10', 'j')
233 >>> mgr.find_user_password("f", "http://g.example.com")
234 ('10', 'j')
235 >>> mgr.find_user_password("g", "h.example.com")
236 ('11', 'k')
237 >>> mgr.find_user_password("g", "h.example.com:80")
238 ('11', 'k')
239 >>> mgr.find_user_password("g", "http://h.example.com:80")
240 ('11', 'k')
241 >>> mgr.find_user_password("h", "i.example.com")
242 (None, None)
243 >>> mgr.find_user_password("h", "i.example.com:80")
244 ('12', 'l')
245 >>> mgr.find_user_password("h", "http://i.example.com:80")
246 ('12', 'l')
247 >>> mgr.find_user_password("i", "j.example.com")
248 ('13', 'm')
249 >>> mgr.find_user_password("i", "j.example.com:80")
250 (None, None)
251 >>> mgr.find_user_password("i", "http://j.example.com")
252 ('13', 'm')
253 >>> mgr.find_user_password("i", "http://j.example.com:80")
254 (None, None)
255
256 """
257
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000258class MockOpener:
259 addheaders = []
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +0000260 def open(self, req, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
261 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000262 def error(self, proto, *args):
263 self.proto, self.args = proto, args
264
265class MockFile:
266 def read(self, count=None): pass
267 def readline(self, count=None): pass
268 def close(self): pass
269
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000270class MockHeaders(dict):
271 def getheaders(self, name):
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000272 return list(self.values())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000273
Guido van Rossum34d19282007-08-09 01:03:29 +0000274class MockResponse(io.StringIO):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000275 def __init__(self, code, msg, headers, data, url=None):
Guido van Rossum34d19282007-08-09 01:03:29 +0000276 io.StringIO.__init__(self, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000277 self.code, self.msg, self.headers, self.url = code, msg, headers, url
278 def info(self):
279 return self.headers
280 def geturl(self):
281 return self.url
282
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000283class MockCookieJar:
284 def add_cookie_header(self, request):
285 self.ach_req = request
286 def extract_cookies(self, response, request):
287 self.ec_req, self.ec_r = request, response
288
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000289class FakeMethod:
290 def __init__(self, meth_name, action, handle):
291 self.meth_name = meth_name
292 self.handle = handle
293 self.action = action
294 def __call__(self, *args):
295 return self.handle(self.meth_name, self.action, *args)
296
Senthil Kumaran47fff872009-12-20 07:10:31 +0000297class MockHTTPResponse(io.IOBase):
298 def __init__(self, fp, msg, status, reason):
299 self.fp = fp
300 self.msg = msg
301 self.status = status
302 self.reason = reason
303 self.code = 200
304
305 def read(self):
306 return ''
307
308 def info(self):
309 return {}
310
311 def geturl(self):
312 return self.url
313
314
315class MockHTTPClass:
316 def __init__(self):
317 self.level = 0
318 self.req_headers = []
319 self.data = None
320 self.raise_on_endheaders = False
Nadeem Vawdabd26b542012-10-21 17:37:43 +0200321 self.sock = None
Senthil Kumaran47fff872009-12-20 07:10:31 +0000322 self._tunnel_headers = {}
323
324 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
325 self.host = host
326 self.timeout = timeout
327 return self
328
329 def set_debuglevel(self, level):
330 self.level = level
331
332 def set_tunnel(self, host, port=None, headers=None):
333 self._tunnel_host = host
334 self._tunnel_port = port
335 if headers:
336 self._tunnel_headers = headers
337 else:
338 self._tunnel_headers.clear()
339
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000340 def request(self, method, url, body=None, headers=None):
Senthil Kumaran47fff872009-12-20 07:10:31 +0000341 self.method = method
342 self.selector = url
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000343 if headers is not None:
344 self.req_headers += headers.items()
Senthil Kumaran47fff872009-12-20 07:10:31 +0000345 self.req_headers.sort()
346 if body:
347 self.data = body
348 if self.raise_on_endheaders:
349 import socket
Andrew Svetlov0832af62012-12-18 23:10:48 +0200350 raise OSError()
Senthil Kumaran47fff872009-12-20 07:10:31 +0000351 def getresponse(self):
352 return MockHTTPResponse(MockFile(), {}, 200, "OK")
353
Victor Stinnera4c45d72011-06-17 14:01:18 +0200354 def close(self):
355 pass
356
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000357class MockHandler:
Thomas Wouters477c8d52006-05-27 19:21:47 +0000358 # useful for testing handler machinery
359 # see add_ordered_mock_handlers() docstring
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000360 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000361 def __init__(self, methods):
362 self._define_methods(methods)
363 def _define_methods(self, methods):
364 for spec in methods:
365 if len(spec) == 2: name, action = spec
366 else: name, action = spec, None
367 meth = FakeMethod(name, action, self.handle)
368 setattr(self.__class__, name, meth)
369 def handle(self, fn_name, action, *args, **kwds):
370 self.parent.calls.append((self, fn_name, args, kwds))
371 if action is None:
372 return None
373 elif action == "return self":
374 return self
375 elif action == "return response":
376 res = MockResponse(200, "OK", {}, "")
377 return res
378 elif action == "return request":
379 return Request("http://blah/")
380 elif action.startswith("error"):
381 code = action[action.rfind(" ")+1:]
382 try:
383 code = int(code)
384 except ValueError:
385 pass
386 res = MockResponse(200, "OK", {}, "")
387 return self.parent.error("http", args[0], res, code, "", {})
388 elif action == "raise":
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000389 raise urllib.error.URLError("blah")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000390 assert False
391 def close(self): pass
392 def add_parent(self, parent):
393 self.parent = parent
394 self.parent.calls = []
395 def __lt__(self, other):
396 if not hasattr(other, "handler_order"):
397 # No handler_order, leave in original order. Yuck.
398 return True
399 return self.handler_order < other.handler_order
400
401def add_ordered_mock_handlers(opener, meth_spec):
402 """Create MockHandlers and add them to an OpenerDirector.
403
404 meth_spec: list of lists of tuples and strings defining methods to define
405 on handlers. eg:
406
407 [["http_error", "ftp_open"], ["http_open"]]
408
409 defines methods .http_error() and .ftp_open() on one handler, and
410 .http_open() on another. These methods just record their arguments and
411 return None. Using a tuple instead of a string causes the method to
412 perform some action (see MockHandler.handle()), eg:
413
414 [["http_error"], [("http_open", "return request")]]
415
416 defines .http_error() on one handler (which simply returns None), and
417 .http_open() on another handler, which returns a Request object.
418
419 """
420 handlers = []
421 count = 0
422 for meths in meth_spec:
423 class MockHandlerSubclass(MockHandler): pass
424 h = MockHandlerSubclass(meths)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000425 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000426 h.add_parent(opener)
427 count = count + 1
428 handlers.append(h)
429 opener.add_handler(h)
430 return handlers
431
Thomas Wouters477c8d52006-05-27 19:21:47 +0000432def build_test_opener(*handler_instances):
433 opener = OpenerDirector()
434 for h in handler_instances:
435 opener.add_handler(h)
436 return opener
437
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000438class MockHTTPHandler(urllib.request.BaseHandler):
Thomas Wouters477c8d52006-05-27 19:21:47 +0000439 # useful for testing redirections and auth
440 # sends supplied headers and code as first response
441 # sends 200 OK as second response
442 def __init__(self, code, headers):
443 self.code = code
444 self.headers = headers
445 self.reset()
446 def reset(self):
447 self._count = 0
448 self.requests = []
449 def http_open(self, req):
Barry Warsaw820c1202008-06-12 04:06:45 +0000450 import email, http.client, copy
Guido van Rossum34d19282007-08-09 01:03:29 +0000451 from io import StringIO
Thomas Wouters477c8d52006-05-27 19:21:47 +0000452 self.requests.append(copy.deepcopy(req))
453 if self._count == 0:
454 self._count = self._count + 1
Georg Brandl24420152008-05-26 16:32:26 +0000455 name = http.client.responses[self.code]
Barry Warsaw820c1202008-06-12 04:06:45 +0000456 msg = email.message_from_string(self.headers)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000457 return self.parent.error(
458 "http", req, MockFile(), self.code, name, msg)
459 else:
460 self.req = req
Barry Warsaw820c1202008-06-12 04:06:45 +0000461 msg = email.message_from_string("\r\n\r\n")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000462 return MockResponse(200, "OK", msg, "", req.get_full_url())
463
Senthil Kumaran47fff872009-12-20 07:10:31 +0000464class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
465 # Useful for testing the Proxy-Authorization request by verifying the
466 # properties of httpcon
Benjamin Peterson3d5b8db2009-12-24 01:14:05 +0000467
468 def __init__(self):
469 urllib.request.AbstractHTTPHandler.__init__(self)
470 self.httpconn = MockHTTPClass()
471
Senthil Kumaran47fff872009-12-20 07:10:31 +0000472 def https_open(self, req):
473 return self.do_open(self.httpconn, req)
474
Thomas Wouters477c8d52006-05-27 19:21:47 +0000475class MockPasswordManager:
476 def add_password(self, realm, uri, user, password):
477 self.realm = realm
478 self.url = uri
479 self.user = user
480 self.password = password
481 def find_user_password(self, realm, authuri):
482 self.target_realm = realm
483 self.target_url = authuri
484 return self.user, self.password
485
486
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000487class OpenerDirectorTests(unittest.TestCase):
488
Guido van Rossumb5a755e2007-07-18 18:15:48 +0000489 def test_add_non_handler(self):
490 class NonHandler(object):
491 pass
492 self.assertRaises(TypeError,
493 OpenerDirector().add_handler, NonHandler())
494
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000495 def test_badly_named_methods(self):
496 # test work-around for three methods that accidentally follow the
497 # naming conventions for handler methods
498 # (*_open() / *_request() / *_response())
499
500 # These used to call the accidentally-named methods, causing a
501 # TypeError in real code; here, returning self from these mock
502 # methods would either cause no exception, or AttributeError.
503
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000504 from urllib.error import URLError
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000505
506 o = OpenerDirector()
507 meth_spec = [
508 [("do_open", "return self"), ("proxy_open", "return self")],
509 [("redirect_request", "return self")],
510 ]
511 handlers = add_ordered_mock_handlers(o, meth_spec)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000512 o.add_handler(urllib.request.UnknownHandler())
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000513 for scheme in "do", "proxy", "redirect":
514 self.assertRaises(URLError, o.open, scheme+"://example.com/")
515
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000516 def test_handled(self):
517 # handler returning non-None means no more handlers will be called
518 o = OpenerDirector()
519 meth_spec = [
520 ["http_open", "ftp_open", "http_error_302"],
521 ["ftp_open"],
522 [("http_open", "return self")],
523 [("http_open", "return self")],
524 ]
525 handlers = add_ordered_mock_handlers(o, meth_spec)
526
527 req = Request("http://example.com/")
528 r = o.open(req)
529 # Second .http_open() gets called, third doesn't, since second returned
530 # non-None. Handlers without .http_open() never get any methods called
531 # on them.
532 # In fact, second mock handler defining .http_open() returns self
533 # (instead of response), which becomes the OpenerDirector's return
534 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000535 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000536 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
537 for expected, got in zip(calls, o.calls):
538 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000539 self.assertEqual((handler, name), expected)
540 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000541
542 def test_handler_order(self):
543 o = OpenerDirector()
544 handlers = []
545 for meths, handler_order in [
546 ([("http_open", "return self")], 500),
547 (["http_open"], 0),
548 ]:
549 class MockHandlerSubclass(MockHandler): pass
550 h = MockHandlerSubclass(meths)
551 h.handler_order = handler_order
552 handlers.append(h)
553 o.add_handler(h)
554
555 r = o.open("http://example.com/")
556 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000557 self.assertEqual(o.calls[0][0], handlers[1])
558 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000559
560 def test_raise(self):
561 # raising URLError stops processing of request
562 o = OpenerDirector()
563 meth_spec = [
564 [("http_open", "raise")],
565 [("http_open", "return self")],
566 ]
567 handlers = add_ordered_mock_handlers(o, meth_spec)
568
569 req = Request("http://example.com/")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000570 self.assertRaises(urllib.error.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000571 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000572
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000573 def test_http_error(self):
574 # XXX http_error_default
575 # http errors are a special case
576 o = OpenerDirector()
577 meth_spec = [
578 [("http_open", "error 302")],
579 [("http_error_400", "raise"), "http_open"],
580 [("http_error_302", "return response"), "http_error_303",
581 "http_error"],
582 [("http_error_302")],
583 ]
584 handlers = add_ordered_mock_handlers(o, meth_spec)
585
586 class Unknown:
587 def __eq__(self, other): return True
588
589 req = Request("http://example.com/")
590 r = o.open(req)
591 assert len(o.calls) == 2
592 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000593 (handlers[2], "http_error_302",
594 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000595 for expected, got in zip(calls, o.calls):
596 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000597 self.assertEqual((handler, method_name), got[:2])
598 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000599
Senthil Kumaran38b968b92012-03-14 13:43:53 -0700600
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000601 def test_processors(self):
602 # *_request / *_response methods get called appropriately
603 o = OpenerDirector()
604 meth_spec = [
605 [("http_request", "return request"),
606 ("http_response", "return response")],
607 [("http_request", "return request"),
608 ("http_response", "return response")],
609 ]
610 handlers = add_ordered_mock_handlers(o, meth_spec)
611
612 req = Request("http://example.com/")
613 r = o.open(req)
614 # processor methods are called on *all* handlers that define them,
615 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000616 calls = [
617 (handlers[0], "http_request"), (handlers[1], "http_request"),
618 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000619
620 for i, (handler, name, args, kwds) in enumerate(o.calls):
621 if i < 2:
622 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000623 self.assertEqual((handler, name), calls[i])
624 self.assertEqual(len(args), 1)
Ezio Melottie9615932010-01-24 19:26:24 +0000625 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000626 else:
627 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000628 self.assertEqual((handler, name), calls[i])
629 self.assertEqual(len(args), 2)
Ezio Melottie9615932010-01-24 19:26:24 +0000630 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000631 # response from opener.open is None, because there's no
632 # handler that defines http_open to handle it
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000633 self.assertTrue(args[1] is None or
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000634 isinstance(args[1], MockResponse))
635
Tim Peters58eb11c2004-01-18 20:29:55 +0000636def sanepathname2url(path):
Victor Stinner6c6f8512010-08-07 10:09:35 +0000637 try:
Marc-André Lemburg8f36af72011-02-25 15:42:01 +0000638 path.encode("utf-8")
Victor Stinner6c6f8512010-08-07 10:09:35 +0000639 except UnicodeEncodeError:
640 raise unittest.SkipTest("path is not encodable to utf8")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000641 urlpath = urllib.request.pathname2url(path)
Tim Peters58eb11c2004-01-18 20:29:55 +0000642 if os.name == "nt" and urlpath.startswith("///"):
643 urlpath = urlpath[2:]
644 # XXX don't ask me about the mac...
645 return urlpath
646
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000647class HandlerTests(unittest.TestCase):
648
649 def test_ftp(self):
650 class MockFTPWrapper:
651 def __init__(self, data): self.data = data
652 def retrfile(self, filename, filetype):
653 self.filename, self.filetype = filename, filetype
Guido van Rossum34d19282007-08-09 01:03:29 +0000654 return io.StringIO(self.data), len(self.data)
Nadeem Vawda08f5f7a2011-07-23 14:03:00 +0200655 def close(self): pass
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000656
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000657 class NullFTPHandler(urllib.request.FTPHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000658 def __init__(self, data): self.data = data
Georg Brandlf78e02b2008-06-10 17:40:04 +0000659 def connect_ftp(self, user, passwd, host, port, dirs,
660 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000661 self.user, self.passwd = user, passwd
662 self.host, self.port = host, port
663 self.dirs = dirs
664 self.ftpwrapper = MockFTPWrapper(self.data)
665 return self.ftpwrapper
666
Georg Brandlf78e02b2008-06-10 17:40:04 +0000667 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000668 data = "rheum rhaponicum"
669 h = NullFTPHandler(data)
670 o = h.parent = MockOpener()
671
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000672 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000673 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000674 "localhost", ftplib.FTP_PORT, "", "", "I",
675 ["foo", "bar"], "baz.html", "text/html"),
676 ("ftp://parrot@localhost/foo/bar/baz.html",
677 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
678 ["foo", "bar"], "baz.html", "text/html"),
679 ("ftp://%25parrot@localhost/foo/bar/baz.html",
680 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
681 ["foo", "bar"], "baz.html", "text/html"),
682 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
683 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000684 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000685 ("ftp://localhost:80/foo/bar/",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000686 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000687 ["foo", "bar"], "", None),
688 ("ftp://localhost/baz.gif;type=a",
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000689 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000690 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000691 ]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000692 req = Request(url)
693 req.timeout = None
694 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000695 # ftp authentication not yet implemented by FTPHandler
Senthil Kumarandaa29d02010-11-18 15:36:41 +0000696 self.assertEqual(h.user, user)
697 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000698 self.assertEqual(h.host, socket.gethostbyname(host))
699 self.assertEqual(h.port, port)
700 self.assertEqual(h.dirs, dirs)
701 self.assertEqual(h.ftpwrapper.filename, filename)
702 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000703 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000704 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000705 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000706
707 def test_file(self):
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000708 import email.utils, socket
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000709 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000710 o = h.parent = MockOpener()
711
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000712 TESTFN = support.TESTFN
Tim Peters58eb11c2004-01-18 20:29:55 +0000713 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Guido van Rossum6a2ccd02007-07-16 20:51:57 +0000714 towrite = b"hello, world\n"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000715 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000716 "file://localhost%s" % urlpath,
717 "file://%s" % urlpath,
718 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000719 ]
720 try:
721 localaddr = socket.gethostbyname(socket.gethostname())
722 except socket.gaierror:
723 localaddr = ''
724 if localaddr:
725 urls.append("file://%s%s" % (localaddr, urlpath))
726
727 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000728 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000729 try:
730 try:
731 f.write(towrite)
732 finally:
733 f.close()
734
735 r = h.file_open(Request(url))
736 try:
737 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000738 headers = r.info()
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000739 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000740 finally:
741 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000742 stats = os.stat(TESTFN)
Benjamin Petersona0c0a4a2008-06-12 22:15:50 +0000743 modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000744 finally:
745 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000746 self.assertEqual(data, towrite)
747 self.assertEqual(headers["Content-type"], "text/plain")
748 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000749 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran4fbed102010-05-08 03:29:09 +0000750 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000751
752 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000753 "file://localhost:80%s" % urlpath,
Guido van Rossumd8faa362007-04-27 19:54:29 +0000754 "file:///file_does_not_exist.txt",
755 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
756 os.getcwd(), TESTFN),
757 "file://somerandomhost.ontheinternet.com%s/%s" %
758 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000759 ]:
760 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000761 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000762 try:
763 f.write(towrite)
764 finally:
765 f.close()
766
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000767 self.assertRaises(urllib.error.URLError,
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000768 h.file_open, Request(url))
769 finally:
770 os.remove(TESTFN)
771
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000772 h = urllib.request.FileHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000773 o = h.parent = MockOpener()
774 # XXXX why does // mean ftp (and /// mean not ftp!), and where
775 # is file: scheme specified? I think this is really a bug, and
776 # what was intended was to distinguish between URLs like:
777 # file:/blah.txt (a file)
778 # file://localhost/blah.txt (a file)
779 # file:///blah.txt (a file)
780 # file://ftp.example.com/blah.txt (an ftp URL)
781 for url, ftp in [
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000782 ("file://ftp.example.com//foo.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000783 ("file://ftp.example.com///foo.txt", False),
784# XXXX bug: fails with OSError, should be URLError
785 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran383c32d2010-10-14 11:57:35 +0000786 ("file://somehost//foo/something.txt", False),
Senthil Kumaran2ef16322010-07-11 03:12:43 +0000787 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000788 ]:
789 req = Request(url)
790 try:
791 h.file_open(req)
792 # XXXX remove OSError when bug fixed
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000793 except (urllib.error.URLError, OSError):
Florent Xicluna419e3842010-08-08 16:16:07 +0000794 self.assertFalse(ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000795 else:
Florent Xicluna419e3842010-08-08 16:16:07 +0000796 self.assertIs(o.req, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000797 self.assertEqual(req.type, "ftp")
Łukasz Langad7e81cc2011-01-09 18:18:53 +0000798 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000799
800 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000801
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000802 h = urllib.request.AbstractHTTPHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000803 o = h.parent = MockOpener()
804
805 url = "http://example.com/"
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000806 for method, data in [("GET", None), ("POST", b"blah")]:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000807 req = Request(url, data, {"Foo": "bar"})
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000808 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000809 req.add_unredirected_header("Spam", "eggs")
810 http = MockHTTPClass()
811 r = h.do_open(http, req)
812
813 # result attributes
814 r.read; r.readline # wrapped MockFile methods
815 r.info; r.geturl # addinfourl methods
816 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
817 hdrs = r.info()
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000818 hdrs.get; hdrs.__contains__ # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000819 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000820
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000821 self.assertEqual(http.host, "example.com")
822 self.assertEqual(http.level, 0)
823 self.assertEqual(http.method, method)
824 self.assertEqual(http.selector, "/")
825 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000826 [("Connection", "close"),
827 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000828 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000829
Andrew Svetlov0832af62012-12-18 23:10:48 +0200830 # check OSError converted to URLError
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000831 http.raise_on_endheaders = True
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000832 self.assertRaises(urllib.error.URLError, h.do_open, http, req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000833
Senthil Kumaran29333122011-02-11 11:25:47 +0000834 # Check for TypeError on POST data which is str.
835 req = Request("http://example.com/","badpost")
836 self.assertRaises(TypeError, h.do_request_, req)
837
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000838 # check adding of standard headers
839 o.addheaders = [("Spam", "eggs")]
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000840 for data in b"", None: # POST, GET
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000841 req = Request("http://example.com/", data)
842 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000843 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000844 if data is None: # GET
Benjamin Peterson577473f2010-01-19 00:09:57 +0000845 self.assertNotIn("Content-length", req.unredirected_hdrs)
846 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000847 else: # POST
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000848 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
849 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000850 "application/x-www-form-urlencoded")
851 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000852 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
853 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000854
855 # don't clobber existing headers
856 req.add_unredirected_header("Content-length", "foo")
857 req.add_unredirected_header("Content-type", "bar")
858 req.add_unredirected_header("Host", "baz")
859 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000860 newreq = h.do_request_(req)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000861 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
862 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000863 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
864 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000865
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000866 # Check iterable body support
867 def iterable_body():
868 yield b"one"
869 yield b"two"
870 yield b"three"
871
872 for headers in {}, {"Content-Length": 11}:
873 req = Request("http://example.com/", iterable_body(), headers)
874 if not headers:
875 # Having an iterable body without a Content-Length should
876 # raise an exception
877 self.assertRaises(ValueError, h.do_request_, req)
878 else:
879 newreq = h.do_request_(req)
880
Senthil Kumaran29333122011-02-11 11:25:47 +0000881 # A file object.
882 # Test only Content-Length attribute of request.
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000883
Senthil Kumaran29333122011-02-11 11:25:47 +0000884 file_obj = io.BytesIO()
885 file_obj.write(b"Something\nSomething\nSomething\n")
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000886
887 for headers in {}, {"Content-Length": 30}:
888 req = Request("http://example.com/", file_obj, headers)
889 if not headers:
890 # Having an iterable body without a Content-Length should
891 # raise an exception
892 self.assertRaises(ValueError, h.do_request_, req)
893 else:
894 newreq = h.do_request_(req)
895 self.assertEqual(int(newreq.get_header('Content-length')),30)
896
897 file_obj.close()
898
899 # array.array Iterable - Content Length is calculated
900
901 iterable_array = array.array("I",[1,2,3,4])
902
903 for headers in {}, {"Content-Length": 16}:
904 req = Request("http://example.com/", iterable_array, headers)
905 newreq = h.do_request_(req)
906 self.assertEqual(int(newreq.get_header('Content-length')),16)
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000907
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000908 def test_http_doubleslash(self):
909 # Checks the presence of any unnecessary double slash in url does not
910 # break anything. Previously, a double slash directly after the host
Ezio Melottie130a522011-10-19 10:58:56 +0300911 # could cause incorrect parsing.
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000912 h = urllib.request.AbstractHTTPHandler()
913 o = h.parent = MockOpener()
914
Senthil Kumaran7bc0d872010-12-19 10:49:52 +0000915 data = b""
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000916 ds_urls = [
917 "http://example.com/foo/bar/baz.html",
918 "http://example.com//foo/bar/baz.html",
919 "http://example.com/foo//bar/baz.html",
920 "http://example.com/foo/bar//baz.html"
921 ]
922
923 for ds_url in ds_urls:
924 ds_req = Request(ds_url, data)
925
926 # Check whether host is determined correctly if there is no proxy
927 np_ds_req = h.do_request_(ds_req)
928 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
929
930 # Check whether host is determined correctly if there is a proxy
931 ds_req.set_proxy("someproxy:3128",None)
932 p_ds_req = h.do_request_(ds_req)
933 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
934
Senthil Kumaranc2958622010-11-22 04:48:26 +0000935 def test_fixpath_in_weirdurls(self):
936 # Issue4493: urllib2 to supply '/' when to urls where path does not
937 # start with'/'
938
939 h = urllib.request.AbstractHTTPHandler()
940 o = h.parent = MockOpener()
941
942 weird_url = 'http://www.python.org?getspam'
943 req = Request(weird_url)
944 newreq = h.do_request_(req)
945 self.assertEqual(newreq.host,'www.python.org')
946 self.assertEqual(newreq.selector,'/?getspam')
947
948 url_without_path = 'http://www.python.org'
949 req = Request(url_without_path)
950 newreq = h.do_request_(req)
951 self.assertEqual(newreq.host,'www.python.org')
952 self.assertEqual(newreq.selector,'')
953
Facundo Batista72dc1ea2008-08-16 14:44:32 +0000954
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000955 def test_errors(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000956 h = urllib.request.HTTPErrorProcessor()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000957 o = h.parent = MockOpener()
958
959 url = "http://example.com/"
960 req = Request(url)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000961 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000962 r = MockResponse(200, "OK", {}, "", url)
963 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000964 self.assertIs(r, newr)
965 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000966 r = MockResponse(202, "Accepted", {}, "", url)
967 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000968 self.assertIs(r, newr)
969 self.assertFalse(hasattr(o, "proto")) # o.error not called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000970 r = MockResponse(206, "Partial content", {}, "", url)
971 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000972 self.assertIs(r, newr)
973 self.assertFalse(hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000974 # anything else calls o.error (and MockOpener returns None, here)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000975 r = MockResponse(502, "Bad gateway", {}, "", url)
Florent Xicluna419e3842010-08-08 16:16:07 +0000976 self.assertIsNone(h.http_response(req, r))
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000977 self.assertEqual(o.proto, "http") # o.error called
Guido van Rossumd8faa362007-04-27 19:54:29 +0000978 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000979
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000980 def test_cookies(self):
981 cj = MockCookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000982 h = urllib.request.HTTPCookieProcessor(cj)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000983 o = h.parent = MockOpener()
984
985 req = Request("http://example.com/")
986 r = MockResponse(200, "OK", {}, "")
987 newreq = h.http_request(req)
Florent Xicluna419e3842010-08-08 16:16:07 +0000988 self.assertIs(cj.ach_req, req)
989 self.assertIs(cj.ach_req, newreq)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -0700990 self.assertEqual(req.origin_req_host, "example.com")
991 self.assertFalse(req.unverifiable)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000992 newr = h.http_response(req, r)
Florent Xicluna419e3842010-08-08 16:16:07 +0000993 self.assertIs(cj.ec_req, req)
994 self.assertIs(cj.ec_r, r)
995 self.assertIs(r, newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000996
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000997 def test_redirect(self):
998 from_url = "http://example.com/a.html"
999 to_url = "http://example.com/b.html"
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001000 h = urllib.request.HTTPRedirectHandler()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001001 o = h.parent = MockOpener()
1002
1003 # ordinary redirect behaviour
1004 for code in 301, 302, 303, 307:
1005 for data in None, "blah\nblah\n":
1006 method = getattr(h, "http_error_%s" % code)
1007 req = Request(from_url, data)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001008 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001009 req.add_header("Nonsense", "viking=withhold")
Christian Heimes77c02eb2008-02-09 02:18:51 +00001010 if data is not None:
1011 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001012 req.add_unredirected_header("Spam", "spam")
1013 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001014 method(req, MockFile(), code, "Blah",
1015 MockHeaders({"location": to_url}))
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001016 except urllib.error.HTTPError:
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001017 # 307 in response to POST requires user OK
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001018 self.assertTrue(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001019 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001020 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001021 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001022 except AttributeError:
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001023 self.assertFalse(o.req.data)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001024
1025 # now it's a GET, there should not be headers regarding content
1026 # (possibly dragged from before being a POST)
1027 headers = [x.lower() for x in o.req.headers]
Benjamin Peterson577473f2010-01-19 00:09:57 +00001028 self.assertNotIn("content-length", headers)
1029 self.assertNotIn("content-type", headers)
Christian Heimes77c02eb2008-02-09 02:18:51 +00001030
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001031 self.assertEqual(o.req.headers["Nonsense"],
1032 "viking=withhold")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001033 self.assertNotIn("Spam", o.req.headers)
1034 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001035
1036 # loop detection
1037 req = Request(from_url)
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001038 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001039 def redirect(h, req, url=to_url):
1040 h.http_error_302(req, MockFile(), 302, "Blah",
1041 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001042 # Note that the *original* request shares the same record of
1043 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001044
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001045 # detect infinite loop redirect of a URL to itself
1046 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001047 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001048 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001049 try:
1050 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001051 redirect(h, req, "http://example.com/")
1052 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001053 except urllib.error.HTTPError:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001054 # don't stop until max_repeats, because cookies may introduce state
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001055 self.assertEqual(count, urllib.request.HTTPRedirectHandler.max_repeats)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001056
1057 # detect endless non-repeating chain of redirects
1058 req = Request(from_url, origin_req_host="example.com")
1059 count = 0
Senthil Kumaranfb8cc2f2009-07-19 02:44:19 +00001060 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001061 try:
1062 while 1:
1063 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001064 count = count + 1
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001065 except urllib.error.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +00001066 self.assertEqual(count,
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001067 urllib.request.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001068
guido@google.coma119df92011-03-29 11:41:02 -07001069
1070 def test_invalid_redirect(self):
1071 from_url = "http://example.com/a.html"
1072 valid_schemes = ['http','https','ftp']
1073 invalid_schemes = ['file','imap','ldap']
1074 schemeless_url = "example.com/b.html"
1075 h = urllib.request.HTTPRedirectHandler()
1076 o = h.parent = MockOpener()
1077 req = Request(from_url)
1078 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1079
1080 for scheme in invalid_schemes:
1081 invalid_url = scheme + '://' + schemeless_url
1082 self.assertRaises(urllib.error.HTTPError, h.http_error_302,
1083 req, MockFile(), 302, "Security Loophole",
1084 MockHeaders({"location": invalid_url}))
1085
1086 for scheme in valid_schemes:
1087 valid_url = scheme + '://' + schemeless_url
1088 h.http_error_302(req, MockFile(), 302, "That's fine",
1089 MockHeaders({"location": valid_url}))
1090 self.assertEqual(o.req.get_full_url(), valid_url)
1091
Senthil Kumaran6497aa32012-01-04 13:46:59 +08001092 def test_relative_redirect(self):
1093 from_url = "http://example.com/a.html"
1094 relative_url = "/b.html"
1095 h = urllib.request.HTTPRedirectHandler()
1096 o = h.parent = MockOpener()
1097 req = Request(from_url)
1098 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
1099
1100 valid_url = urllib.parse.urljoin(from_url,relative_url)
1101 h.http_error_302(req, MockFile(), 302, "That's fine",
1102 MockHeaders({"location": valid_url}))
1103 self.assertEqual(o.req.get_full_url(), valid_url)
1104
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001105 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001106 # cookies shouldn't leak into redirected requests
Georg Brandl24420152008-05-26 16:32:26 +00001107 from http.cookiejar import CookieJar
1108 from test.test_http_cookiejar import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001109
1110 cj = CookieJar()
1111 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Thomas Wouters477c8d52006-05-27 19:21:47 +00001112 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001113 hdeh = urllib.request.HTTPDefaultErrorHandler()
1114 hrh = urllib.request.HTTPRedirectHandler()
1115 cp = urllib.request.HTTPCookieProcessor(cj)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001116 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001117 o.open("http://www.example.com/")
Florent Xicluna419e3842010-08-08 16:16:07 +00001118 self.assertFalse(hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001119
Senthil Kumaran26430412011-04-13 07:01:19 +08001120 def test_redirect_fragment(self):
1121 redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
1122 hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
1123 hdeh = urllib.request.HTTPDefaultErrorHandler()
1124 hrh = urllib.request.HTTPRedirectHandler()
1125 o = build_test_opener(hh, hdeh, hrh)
1126 fp = o.open('http://www.example.com')
1127 self.assertEqual(fp.geturl(), redirected_url.strip())
1128
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001129 def test_proxy(self):
1130 o = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001131 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001132 o.add_handler(ph)
1133 meth_spec = [
1134 [("http_open", "return response")]
1135 ]
1136 handlers = add_ordered_mock_handlers(o, meth_spec)
1137
1138 req = Request("http://acme.example.com/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001139 self.assertEqual(req.host, "acme.example.com")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001140 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001141 self.assertEqual(req.host, "proxy.example.com:3128")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001142
1143 self.assertEqual([(handlers[0], "http_open")],
1144 [tup[0:2] for tup in o.calls])
1145
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001146 def test_proxy_no_proxy(self):
1147 os.environ['no_proxy'] = 'python.org'
1148 o = OpenerDirector()
1149 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1150 o.add_handler(ph)
1151 req = Request("http://www.perl.org/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001152 self.assertEqual(req.host, "www.perl.org")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001153 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001154 self.assertEqual(req.host, "proxy.example.com")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001155 req = Request("http://www.python.org")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001156 self.assertEqual(req.host, "www.python.org")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001157 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001158 self.assertEqual(req.host, "www.python.org")
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001159 del os.environ['no_proxy']
1160
Ronald Oussorene72e1612011-03-14 18:15:25 -04001161 def test_proxy_no_proxy_all(self):
1162 os.environ['no_proxy'] = '*'
1163 o = OpenerDirector()
1164 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
1165 o.add_handler(ph)
1166 req = Request("http://www.python.org")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001167 self.assertEqual(req.host, "www.python.org")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001168 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001169 self.assertEqual(req.host, "www.python.org")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001170 del os.environ['no_proxy']
1171
Senthil Kumaran7bb04972009-10-11 04:58:55 +00001172
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001173 def test_proxy_https(self):
1174 o = OpenerDirector()
1175 ph = urllib.request.ProxyHandler(dict(https="proxy.example.com:3128"))
1176 o.add_handler(ph)
1177 meth_spec = [
1178 [("https_open", "return response")]
1179 ]
1180 handlers = add_ordered_mock_handlers(o, meth_spec)
1181
1182 req = Request("https://www.example.com/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001183 self.assertEqual(req.host, "www.example.com")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001184 r = o.open(req)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001185 self.assertEqual(req.host, "proxy.example.com:3128")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001186 self.assertEqual([(handlers[0], "https_open")],
1187 [tup[0:2] for tup in o.calls])
1188
Senthil Kumaran47fff872009-12-20 07:10:31 +00001189 def test_proxy_https_proxy_authorization(self):
1190 o = OpenerDirector()
1191 ph = urllib.request.ProxyHandler(dict(https='proxy.example.com:3128'))
1192 o.add_handler(ph)
1193 https_handler = MockHTTPSHandler()
1194 o.add_handler(https_handler)
1195 req = Request("https://www.example.com/")
1196 req.add_header("Proxy-Authorization","FooBar")
1197 req.add_header("User-Agent","Grail")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001198 self.assertEqual(req.host, "www.example.com")
Senthil Kumaran47fff872009-12-20 07:10:31 +00001199 self.assertIsNone(req._tunnel_host)
1200 r = o.open(req)
1201 # Verify Proxy-Authorization gets tunneled to request.
1202 # httpsconn req_headers do not have the Proxy-Authorization header but
1203 # the req will have.
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001204 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran47fff872009-12-20 07:10:31 +00001205 https_handler.httpconn.req_headers)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001206 self.assertIn(("User-Agent","Grail"),
1207 https_handler.httpconn.req_headers)
Senthil Kumaran47fff872009-12-20 07:10:31 +00001208 self.assertIsNotNone(req._tunnel_host)
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001209 self.assertEqual(req.host, "proxy.example.com:3128")
Senthil Kumaran47fff872009-12-20 07:10:31 +00001210 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
Senthil Kumaran97f0c6b2009-07-25 04:24:38 +00001211
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001212 # TODO: This should be only for OSX
1213 @unittest.skipUnless(sys.platform == 'darwin', "only relevant for OSX")
Ronald Oussorene72e1612011-03-14 18:15:25 -04001214 def test_osx_proxy_bypass(self):
1215 bypass = {
1216 'exclude_simple': False,
1217 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
1218 '10.0/16']
1219 }
1220 # Check hosts that should trigger the proxy bypass
1221 for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
1222 '10.0.0.1'):
1223 self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
1224 'expected bypass of %s to be True' % host)
1225 # Check hosts that should not trigger the proxy bypass
1226 for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
1227 self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
1228 'expected bypass of %s to be False' % host)
1229
1230 # Check the exclude_simple flag
1231 bypass = {'exclude_simple': True, 'exceptions': []}
1232 self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
1233
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001234 def test_basic_auth(self, quote_char='"'):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001235 opener = OpenerDirector()
1236 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001237 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001238 realm = "ACME Widget Store"
1239 http_handler = MockHTTPHandler(
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001240 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1241 (quote_char, realm, quote_char) )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001242 opener.add_handler(auth_handler)
1243 opener.add_handler(http_handler)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001244 self._test_basic_auth(opener, auth_handler, "Authorization",
1245 realm, http_handler, password_manager,
1246 "http://acme.example.com/protected",
1247 "http://acme.example.com/protected",
1248 )
1249
Christian Heimes4fbc72b2008-03-22 00:47:35 +00001250 def test_basic_auth_with_single_quoted_realm(self):
1251 self.test_basic_auth(quote_char="'")
1252
Senthil Kumaran34f3fcc2012-05-15 22:30:25 +08001253 def test_basic_auth_with_unquoted_realm(self):
1254 opener = OpenerDirector()
1255 password_manager = MockPasswordManager()
1256 auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
1257 realm = "ACME Widget Store"
1258 http_handler = MockHTTPHandler(
1259 401, 'WWW-Authenticate: Basic realm=%s\r\n\r\n' % realm)
1260 opener.add_handler(auth_handler)
1261 opener.add_handler(http_handler)
Senthil Kumaran0ea91cb2012-05-15 23:59:42 +08001262 with self.assertWarns(UserWarning):
1263 self._test_basic_auth(opener, auth_handler, "Authorization",
1264 realm, http_handler, password_manager,
1265 "http://acme.example.com/protected",
1266 "http://acme.example.com/protected",
1267 )
Senthil Kumaran34f3fcc2012-05-15 22:30:25 +08001268
Thomas Wouters477c8d52006-05-27 19:21:47 +00001269 def test_proxy_basic_auth(self):
1270 opener = OpenerDirector()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001271 ph = urllib.request.ProxyHandler(dict(http="proxy.example.com:3128"))
Thomas Wouters477c8d52006-05-27 19:21:47 +00001272 opener.add_handler(ph)
1273 password_manager = MockPasswordManager()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001274 auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001275 realm = "ACME Networks"
1276 http_handler = MockHTTPHandler(
1277 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001278 opener.add_handler(auth_handler)
1279 opener.add_handler(http_handler)
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001280 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Thomas Wouters477c8d52006-05-27 19:21:47 +00001281 realm, http_handler, password_manager,
1282 "http://acme.example.com:3128/protected",
1283 "proxy.example.com:3128",
1284 )
1285
1286 def test_basic_and_digest_auth_handlers(self):
Andrew Svetlov7bd61cb2012-12-19 22:49:25 +02001287 # HTTPDigestAuthHandler raised an exception if it couldn't handle a 40*
Thomas Wouters477c8d52006-05-27 19:21:47 +00001288 # response (http://python.org/sf/1479302), where it should instead
1289 # return None to allow another handler (especially
1290 # HTTPBasicAuthHandler) to handle the response.
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001291
1292 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1293 # try digest first (since it's the strongest auth scheme), so we record
1294 # order of calls here to check digest comes first:
1295 class RecordingOpenerDirector(OpenerDirector):
1296 def __init__(self):
1297 OpenerDirector.__init__(self)
1298 self.recorded = []
1299 def record(self, info):
1300 self.recorded.append(info)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001301 class TestDigestAuthHandler(urllib.request.HTTPDigestAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001302 def http_error_401(self, *args, **kwds):
1303 self.parent.record("digest")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001304 urllib.request.HTTPDigestAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001305 *args, **kwds)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001306 class TestBasicAuthHandler(urllib.request.HTTPBasicAuthHandler):
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001307 def http_error_401(self, *args, **kwds):
1308 self.parent.record("basic")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001309 urllib.request.HTTPBasicAuthHandler.http_error_401(self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001310 *args, **kwds)
1311
1312 opener = RecordingOpenerDirector()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001313 password_manager = MockPasswordManager()
1314 digest_handler = TestDigestAuthHandler(password_manager)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001315 basic_handler = TestBasicAuthHandler(password_manager)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001316 realm = "ACME Networks"
1317 http_handler = MockHTTPHandler(
1318 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001319 opener.add_handler(basic_handler)
1320 opener.add_handler(digest_handler)
1321 opener.add_handler(http_handler)
1322
1323 # check basic auth isn't blocked by digest handler failing
Thomas Wouters477c8d52006-05-27 19:21:47 +00001324 self._test_basic_auth(opener, basic_handler, "Authorization",
1325 realm, http_handler, password_manager,
1326 "http://acme.example.com/protected",
1327 "http://acme.example.com/protected",
1328 )
Thomas Wouters4d70c3d2006-06-08 14:42:34 +00001329 # check digest was tried before basic (twice, because
1330 # _test_basic_auth called .open() twice)
1331 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001332
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001333 def test_unsupported_auth_digest_handler(self):
1334 opener = OpenerDirector()
1335 # While using DigestAuthHandler
1336 digest_auth_handler = urllib.request.HTTPDigestAuthHandler(None)
1337 http_handler = MockHTTPHandler(
1338 401, 'WWW-Authenticate: Kerberos\r\n\r\n')
1339 opener.add_handler(digest_auth_handler)
1340 opener.add_handler(http_handler)
1341 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1342
1343 def test_unsupported_auth_basic_handler(self):
1344 # While using BasicAuthHandler
1345 opener = OpenerDirector()
1346 basic_auth_handler = urllib.request.HTTPBasicAuthHandler(None)
1347 http_handler = MockHTTPHandler(
1348 401, 'WWW-Authenticate: NTLM\r\n\r\n')
1349 opener.add_handler(basic_auth_handler)
1350 opener.add_handler(http_handler)
1351 self.assertRaises(ValueError,opener.open,"http://www.example.com")
1352
Thomas Wouters477c8d52006-05-27 19:21:47 +00001353 def _test_basic_auth(self, opener, auth_handler, auth_header,
1354 realm, http_handler, password_manager,
1355 request_url, protected_url):
Christian Heimes05e8be12008-02-23 18:30:17 +00001356 import base64
Thomas Wouters477c8d52006-05-27 19:21:47 +00001357 user, password = "wile", "coyote"
Thomas Wouters477c8d52006-05-27 19:21:47 +00001358
1359 # .add_password() fed through to password manager
1360 auth_handler.add_password(realm, request_url, user, password)
1361 self.assertEqual(realm, password_manager.realm)
1362 self.assertEqual(request_url, password_manager.url)
1363 self.assertEqual(user, password_manager.user)
1364 self.assertEqual(password, password_manager.password)
1365
1366 r = opener.open(request_url)
1367
1368 # should have asked the password manager for the username/password
1369 self.assertEqual(password_manager.target_realm, realm)
1370 self.assertEqual(password_manager.target_url, protected_url)
1371
1372 # expect one request without authorization, then one with
1373 self.assertEqual(len(http_handler.requests), 2)
1374 self.assertFalse(http_handler.requests[0].has_header(auth_header))
Guido van Rossum98b349f2007-08-27 21:47:52 +00001375 userpass = bytes('%s:%s' % (user, password), "ascii")
Guido van Rossum98297ee2007-11-06 21:34:58 +00001376 auth_hdr_value = ('Basic ' +
Georg Brandl706824f2009-06-04 09:42:55 +00001377 base64.encodebytes(userpass).strip().decode())
Thomas Wouters477c8d52006-05-27 19:21:47 +00001378 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1379 auth_hdr_value)
Senthil Kumaranca2fc9e2010-02-24 16:53:16 +00001380 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1381 auth_hdr_value)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001382 # if the password manager can't find a password, the handler won't
1383 # handle the HTTP auth error
1384 password_manager.user = password_manager.password = None
1385 http_handler.reset()
1386 r = opener.open(request_url)
1387 self.assertEqual(len(http_handler.requests), 1)
1388 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1389
Senthil Kumaran4de00a22011-05-11 21:17:57 +08001390
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001391class MiscTests(unittest.TestCase):
1392
Senthil Kumarane9853da2013-03-19 12:07:43 -07001393 def opener_has_handler(self, opener, handler_class):
1394 self.assertTrue(any(h.__class__ == handler_class
1395 for h in opener.handlers))
1396
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001397 def test_build_opener(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001398 class MyHTTPHandler(urllib.request.HTTPHandler): pass
1399 class FooHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001400 def foo_open(self): pass
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001401 class BarHandler(urllib.request.BaseHandler):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001402 def bar_open(self): pass
1403
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001404 build_opener = urllib.request.build_opener
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001405
1406 o = build_opener(FooHandler, BarHandler)
1407 self.opener_has_handler(o, FooHandler)
1408 self.opener_has_handler(o, BarHandler)
1409
1410 # can take a mix of classes and instances
1411 o = build_opener(FooHandler, BarHandler())
1412 self.opener_has_handler(o, FooHandler)
1413 self.opener_has_handler(o, BarHandler)
1414
1415 # subclasses of default handlers override default handlers
1416 o = build_opener(MyHTTPHandler)
1417 self.opener_has_handler(o, MyHTTPHandler)
1418
1419 # a particular case of overriding: default handlers can be passed
1420 # in explicitly
1421 o = build_opener()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001422 self.opener_has_handler(o, urllib.request.HTTPHandler)
1423 o = build_opener(urllib.request.HTTPHandler)
1424 self.opener_has_handler(o, urllib.request.HTTPHandler)
1425 o = build_opener(urllib.request.HTTPHandler())
1426 self.opener_has_handler(o, urllib.request.HTTPHandler)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001427
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001428 # Issue2670: multiple handlers sharing the same base class
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001429 class MyOtherHTTPHandler(urllib.request.HTTPHandler): pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +00001430 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1431 self.opener_has_handler(o, MyHTTPHandler)
1432 self.opener_has_handler(o, MyOtherHTTPHandler)
1433
Brett Cannon80512de2013-01-25 22:27:21 -05001434 @unittest.skipUnless(support.is_resource_enabled('network'),
1435 'test requires network access')
Andrew Svetlovbff98fe2012-11-27 23:06:19 +02001436 def test_issue16464(self):
1437 opener = urllib.request.build_opener()
1438 request = urllib.request.Request("http://www.python.org/~jeremy/")
1439 self.assertEqual(None, request.data)
1440
1441 opener.open(request, "1".encode("us-ascii"))
1442 self.assertEqual(b"1", request.data)
1443 self.assertEqual("1", request.get_header("Content-length"))
1444
1445 opener.open(request, "1234567890".encode("us-ascii"))
1446 self.assertEqual(b"1234567890", request.data)
1447 self.assertEqual("10", request.get_header("Content-length"))
1448
Senthil Kumarane9853da2013-03-19 12:07:43 -07001449 def test_HTTPError_interface(self):
1450 """
1451 Issue 13211 reveals that HTTPError didn't implement the URLError
1452 interface even though HTTPError is a subclass of URLError.
Andrew Svetlovbff98fe2012-11-27 23:06:19 +02001453
Senthil Kumarane9853da2013-03-19 12:07:43 -07001454 >>> msg = 'something bad happened'
1455 >>> url = code = fp = None
1456 >>> hdrs = 'Content-Length: 42'
1457 >>> err = urllib.error.HTTPError(url, code, msg, hdrs, fp)
1458 >>> assert hasattr(err, 'reason')
1459 >>> err.reason
1460 'something bad happened'
1461 >>> assert hasattr(err, 'headers')
1462 >>> err.headers
1463 'Content-Length: 42'
Senthil Kumaran94f27882013-03-19 16:52:06 -07001464 >>> expected_errmsg = 'HTTP Error %s: %s' % (err.code, err.msg)
1465 >>> assert str(err) == expected_errmsg
Senthil Kumarane9853da2013-03-19 12:07:43 -07001466 """
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001467
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001468class RequestTests(unittest.TestCase):
1469
1470 def setUp(self):
1471 self.get = Request("http://www.python.org/~jeremy/")
1472 self.post = Request("http://www.python.org/~jeremy/",
1473 "data",
1474 headers={"X-Test": "test"})
1475
1476 def test_method(self):
1477 self.assertEqual("POST", self.post.get_method())
1478 self.assertEqual("GET", self.get.get_method())
1479
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001480 def test_data(self):
1481 self.assertFalse(self.get.data)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001482 self.assertEqual("GET", self.get.get_method())
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001483 self.get.data = "spam"
1484 self.assertTrue(self.get.data)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001485 self.assertEqual("POST", self.get.get_method())
1486
Andrew Svetlovbff98fe2012-11-27 23:06:19 +02001487 # issue 16464
1488 # if we change data we need to remove content-length header
1489 # (cause it's most probably calculated for previous value)
1490 def test_setting_data_should_remove_content_length(self):
R David Murray9cc7d452013-03-20 00:10:51 -04001491 self.assertNotIn("Content-length", self.get.unredirected_hdrs)
Andrew Svetlovbff98fe2012-11-27 23:06:19 +02001492 self.get.add_unredirected_header("Content-length", 42)
1493 self.assertEqual(42, self.get.unredirected_hdrs["Content-length"])
1494 self.get.data = "spam"
R David Murray9cc7d452013-03-20 00:10:51 -04001495 self.assertNotIn("Content-length", self.get.unredirected_hdrs)
1496
1497 # issue 17485 same for deleting data.
1498 def test_deleting_data_should_remove_content_length(self):
1499 self.assertNotIn("Content-length", self.get.unredirected_hdrs)
1500 self.get.data = 'foo'
1501 self.get.add_unredirected_header("Content-length", 3)
1502 self.assertEqual(3, self.get.unredirected_hdrs["Content-length"])
1503 del self.get.data
1504 self.assertNotIn("Content-length", self.get.unredirected_hdrs)
Andrew Svetlovbff98fe2012-11-27 23:06:19 +02001505
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001506 def test_get_full_url(self):
1507 self.assertEqual("http://www.python.org/~jeremy/",
1508 self.get.get_full_url())
1509
1510 def test_selector(self):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001511 self.assertEqual("/~jeremy/", self.get.selector)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001512 req = Request("http://www.python.org/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001513 self.assertEqual("/", req.selector)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001514
1515 def test_get_type(self):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001516 self.assertEqual("http", self.get.type)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001517
1518 def test_get_host(self):
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001519 self.assertEqual("www.python.org", self.get.host)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001520
1521 def test_get_host_unquote(self):
1522 req = Request("http://www.%70ython.org/")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001523 self.assertEqual("www.python.org", req.host)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001524
1525 def test_proxy(self):
Florent Xicluna419e3842010-08-08 16:16:07 +00001526 self.assertFalse(self.get.has_proxy())
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001527 self.get.set_proxy("www.perl.org", "http")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001528 self.assertTrue(self.get.has_proxy())
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001529 self.assertEqual("www.python.org", self.get.origin_req_host)
1530 self.assertEqual("www.perl.org", self.get.host)
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001531
Senthil Kumarand95cc752010-08-08 11:27:53 +00001532 def test_wrapped_url(self):
1533 req = Request("<URL:http://www.python.org>")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001534 self.assertEqual("www.python.org", req.host)
Senthil Kumarand95cc752010-08-08 11:27:53 +00001535
Senthil Kumaran26430412011-04-13 07:01:19 +08001536 def test_url_fragment(self):
Senthil Kumarand95cc752010-08-08 11:27:53 +00001537 req = Request("http://www.python.org/?qs=query#fragment=true")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001538 self.assertEqual("/?qs=query", req.selector)
Senthil Kumarand95cc752010-08-08 11:27:53 +00001539 req = Request("http://www.python.org/#fun=true")
Senthil Kumaran77ebfcc2012-08-20 13:43:59 -07001540 self.assertEqual("/", req.selector)
Senthil Kumarand95cc752010-08-08 11:27:53 +00001541
Senthil Kumaran26430412011-04-13 07:01:19 +08001542 # Issue 11703: geturl() omits fragment in the original URL.
1543 url = 'http://docs.python.org/library/urllib2.html#OK'
1544 req = Request(url)
1545 self.assertEqual(req.get_full_url(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001546
1547def test_main(verbose=None):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001548 from test import test_urllib2
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001549 support.run_doctest(test_urllib2, verbose)
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001550 support.run_doctest(urllib.request, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001551 tests = (TrivialTests,
1552 OpenerDirectorTests,
1553 HandlerTests,
Benjamin Peterson6ebe78f2008-12-21 00:06:59 +00001554 MiscTests,
1555 RequestTests)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001556 support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001557
1558if __name__ == "__main__":
1559 test_main(verbose=True)