blob: 30c3d2b46422d0771232ce6da51e12c8746a2c21 [file] [log] [blame]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001import unittest
2from test import test_support
Serhiy Storchakaa898abd2014-09-06 21:41:39 +03003from test import test_urllib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00004
Christian Heimesc5f05e42008-02-23 17:40:11 +00005import os
Facundo Batista4f1b1ed2008-05-29 16:39:26 +00006import socket
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00007import StringIO
Jeremy Hyltone3e61042001-05-09 15:50:25 +00008
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00009import urllib2
Berker Peksag87640b32016-03-06 16:27:23 +020010from urllib2 import Request, OpenerDirector, AbstractDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000011
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -060012try:
13 import ssl
14except ImportError:
15 ssl = None
16
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000017# XXX
18# Request
19# CacheFTPHandler (hard to write)
Georg Brandlfa42bd72006-04-30 07:06:11 +000020# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000021
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000022class TrivialTests(unittest.TestCase):
23 def test_trivial(self):
24 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000025
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000026 self.assertRaises(ValueError, urllib2.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000027
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000028 # XXX Name hacking to get this to work on Windows.
Serhiy Storchaka38a33ec2015-01-26 10:26:00 +020029 fname = os.path.abspath(urllib2.__file__).replace(os.sep, '/')
Senthil Kumaran2e3da142010-01-10 17:35:05 +000030
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000031 # And more hacking to get it to work on MacOS. This assumes
32 # urllib.pathname2url works, unfortunately...
Ronald Oussoren9545a232010-05-05 19:09:31 +000033 if os.name == 'riscos':
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000034 import string
35 fname = os.expand(fname)
36 fname = fname.translate(string.maketrans("/.", "./"))
37
Senthil Kumaran2e3da142010-01-10 17:35:05 +000038 if os.name == 'nt':
39 file_url = "file:///%s" % fname
40 else:
41 file_url = "file://%s" % fname
42
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000043 f = urllib2.urlopen(file_url)
44
45 buf = f.read()
46 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000047
Georg Brandle1b13d22005-08-24 22:20:32 +000048 def test_parse_http_list(self):
49 tests = [('a,b,c', ['a', 'b', 'c']),
50 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
51 ('a, b, "c", "d", "e,f", g, h', ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
52 ('a="b\\"c", d="e\\,f", g="h\\\\i"', ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
53 for string, list in tests:
Ezio Melotti2623a372010-11-21 13:34:58 +000054 self.assertEqual(urllib2.parse_http_list(string), list)
Georg Brandle1b13d22005-08-24 22:20:32 +000055
Benjamin Petersonfcfb18e2014-11-23 11:42:45 -060056 @unittest.skipUnless(ssl, "ssl module required")
57 def test_cafile_and_context(self):
58 context = ssl.create_default_context()
59 with self.assertRaises(ValueError):
60 urllib2.urlopen(
61 "https://localhost", cafile="/nonexistent/path", context=context
62 )
63
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000064
Georg Brandl8c036cc2006-08-20 13:15:39 +000065def test_request_headers_dict():
66 """
67 The Request.headers dictionary is not a documented interface. It should
68 stay that way, because the complete set of headers are only accessible
69 through the .get_header(), .has_header(), .header_items() interface.
70 However, .headers pre-dates those methods, and so real code will be using
71 the dictionary.
72
73 The introduction in 2.4 of those methods was a mistake for the same reason:
74 code that previously saw all (urllib2 user)-provided headers in .headers
75 now sees only a subset (and the function interface is ugly and incomplete).
76 A better change would have been to replace .headers dict with a dict
77 subclass (or UserDict.DictMixin instance?) that preserved the .headers
78 interface and also provided access to the "unredirected" headers. It's
79 probably too late to fix that, though.
80
81
82 Check .capitalize() case normalization:
83
84 >>> url = "http://example.com"
85 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
86 'blah'
87 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
88 'blah'
89
90 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
91 but that could be changed in future.
92
93 """
94
95def test_request_headers_methods():
96 """
97 Note the case normalization of header names here, to .capitalize()-case.
98 This should be preserved for backwards-compatibility. (In the HTTP case,
99 normalization to .title()-case is done by urllib2 before sending headers to
100 httplib).
101
102 >>> url = "http://example.com"
103 >>> r = Request(url, headers={"Spam-eggs": "blah"})
104 >>> r.has_header("Spam-eggs")
105 True
106 >>> r.header_items()
107 [('Spam-eggs', 'blah')]
108 >>> r.add_header("Foo-Bar", "baz")
109 >>> items = r.header_items()
110 >>> items.sort()
111 >>> items
112 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
113
114 Note that e.g. r.has_header("spam-EggS") is currently False, and
115 r.get_header("spam-EggS") returns None, but that could be changed in
116 future.
117
118 >>> r.has_header("Not-there")
119 False
120 >>> print r.get_header("Not-there")
121 None
122 >>> r.get_header("Not-there", "default")
123 'default'
124
125 """
126
127
Georg Brandlfa42bd72006-04-30 07:06:11 +0000128def test_password_manager(self):
129 """
130 >>> mgr = urllib2.HTTPPasswordMgr()
131 >>> add = mgr.add_password
132 >>> add("Some Realm", "http://example.com/", "joe", "password")
133 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
134 >>> add("c", "http://example.com/foo", "foo", "ni")
135 >>> add("c", "http://example.com/bar", "bar", "nini")
136 >>> add("b", "http://example.com/", "first", "blah")
137 >>> add("b", "http://example.com/", "second", "spam")
138 >>> add("a", "http://example.com", "1", "a")
139 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
140 >>> add("Some Realm", "d.example.com", "4", "d")
141 >>> add("Some Realm", "e.example.com:3128", "5", "e")
142
143 >>> mgr.find_user_password("Some Realm", "example.com")
144 ('joe', 'password')
145 >>> mgr.find_user_password("Some Realm", "http://example.com")
146 ('joe', 'password')
147 >>> mgr.find_user_password("Some Realm", "http://example.com/")
148 ('joe', 'password')
149 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
150 ('joe', 'password')
151 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
152 ('joe', 'password')
153 >>> mgr.find_user_password("c", "http://example.com/foo")
154 ('foo', 'ni')
155 >>> mgr.find_user_password("c", "http://example.com/bar")
156 ('bar', 'nini')
157
Georg Brandl2b330372006-05-28 20:23:12 +0000158 Actually, this is really undefined ATM
159## Currently, we use the highest-level path where more than one match:
Georg Brandlfa42bd72006-04-30 07:06:11 +0000160
Georg Brandl2b330372006-05-28 20:23:12 +0000161## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
162## ('joe', 'password')
Georg Brandlfa42bd72006-04-30 07:06:11 +0000163
164 Use latest add_password() in case of conflict:
165
166 >>> mgr.find_user_password("b", "http://example.com/")
167 ('second', 'spam')
168
169 No special relationship between a.example.com and example.com:
170
171 >>> mgr.find_user_password("a", "http://example.com/")
172 ('1', 'a')
173 >>> mgr.find_user_password("a", "http://a.example.com/")
174 (None, None)
175
176 Ports:
177
178 >>> mgr.find_user_password("Some Realm", "c.example.com")
179 (None, None)
180 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
181 ('3', 'c')
182 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
183 ('3', 'c')
184 >>> mgr.find_user_password("Some Realm", "d.example.com")
185 ('4', 'd')
186 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
187 ('5', 'e')
188
189 """
190 pass
191
192
Georg Brandl2b330372006-05-28 20:23:12 +0000193def test_password_manager_default_port(self):
194 """
195 >>> mgr = urllib2.HTTPPasswordMgr()
196 >>> add = mgr.add_password
197
198 The point to note here is that we can't guess the default port if there's
199 no scheme. This applies to both add_password and find_user_password.
200
201 >>> add("f", "http://g.example.com:80", "10", "j")
202 >>> add("g", "http://h.example.com", "11", "k")
203 >>> add("h", "i.example.com:80", "12", "l")
204 >>> add("i", "j.example.com", "13", "m")
205 >>> mgr.find_user_password("f", "g.example.com:100")
206 (None, None)
207 >>> mgr.find_user_password("f", "g.example.com:80")
208 ('10', 'j')
209 >>> mgr.find_user_password("f", "g.example.com")
210 (None, None)
211 >>> mgr.find_user_password("f", "http://g.example.com:100")
212 (None, None)
213 >>> mgr.find_user_password("f", "http://g.example.com:80")
214 ('10', 'j')
215 >>> mgr.find_user_password("f", "http://g.example.com")
216 ('10', 'j')
217 >>> mgr.find_user_password("g", "h.example.com")
218 ('11', 'k')
219 >>> mgr.find_user_password("g", "h.example.com:80")
220 ('11', 'k')
221 >>> mgr.find_user_password("g", "http://h.example.com:80")
222 ('11', 'k')
223 >>> mgr.find_user_password("h", "i.example.com")
224 (None, None)
225 >>> mgr.find_user_password("h", "i.example.com:80")
226 ('12', 'l')
227 >>> mgr.find_user_password("h", "http://i.example.com:80")
228 ('12', 'l')
229 >>> mgr.find_user_password("i", "j.example.com")
230 ('13', 'm')
231 >>> mgr.find_user_password("i", "j.example.com:80")
232 (None, None)
233 >>> mgr.find_user_password("i", "http://j.example.com")
234 ('13', 'm')
235 >>> mgr.find_user_password("i", "http://j.example.com:80")
236 (None, None)
237
238 """
239
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000240class MockOpener:
241 addheaders = []
Senthil Kumaran5fee4602009-07-19 02:43:43 +0000242 def open(self, req, data=None,timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
243 self.req, self.data, self.timeout = req, data, timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000244 def error(self, proto, *args):
245 self.proto, self.args = proto, args
246
247class MockFile:
248 def read(self, count=None): pass
249 def readline(self, count=None): pass
250 def close(self): pass
251
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000252class MockHeaders(dict):
253 def getheaders(self, name):
254 return self.values()
255
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000256class MockResponse(StringIO.StringIO):
257 def __init__(self, code, msg, headers, data, url=None):
258 StringIO.StringIO.__init__(self, data)
259 self.code, self.msg, self.headers, self.url = code, msg, headers, url
260 def info(self):
261 return self.headers
262 def geturl(self):
263 return self.url
264
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000265class MockCookieJar:
266 def add_cookie_header(self, request):
267 self.ach_req = request
268 def extract_cookies(self, response, request):
269 self.ec_req, self.ec_r = request, response
270
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000271class FakeMethod:
272 def __init__(self, meth_name, action, handle):
273 self.meth_name = meth_name
274 self.handle = handle
275 self.action = action
276 def __call__(self, *args):
277 return self.handle(self.meth_name, self.action, *args)
278
Senthil Kumaran7713acf2009-12-20 06:05:13 +0000279class MockHTTPResponse:
280 def __init__(self, fp, msg, status, reason):
281 self.fp = fp
282 self.msg = msg
283 self.status = status
284 self.reason = reason
285 def read(self):
286 return ''
287
288class MockHTTPClass:
289 def __init__(self):
290 self.req_headers = []
291 self.data = None
292 self.raise_on_endheaders = False
293 self._tunnel_headers = {}
294
295 def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
296 self.host = host
297 self.timeout = timeout
298 return self
299
300 def set_debuglevel(self, level):
301 self.level = level
302
303 def set_tunnel(self, host, port=None, headers=None):
304 self._tunnel_host = host
305 self._tunnel_port = port
306 if headers:
307 self._tunnel_headers = headers
308 else:
309 self._tunnel_headers.clear()
Victor Stinnerc74a6ba2011-06-17 14:06:27 +0200310
Benjamin Peterson32935932009-12-24 01:09:53 +0000311 def request(self, method, url, body=None, headers=None):
Senthil Kumaran7713acf2009-12-20 06:05:13 +0000312 self.method = method
313 self.selector = url
Benjamin Peterson32935932009-12-24 01:09:53 +0000314 if headers is not None:
315 self.req_headers += headers.items()
Senthil Kumaran7713acf2009-12-20 06:05:13 +0000316 self.req_headers.sort()
317 if body:
318 self.data = body
319 if self.raise_on_endheaders:
320 import socket
321 raise socket.error()
Victor Stinnerc74a6ba2011-06-17 14:06:27 +0200322
Senthil Kumaran7713acf2009-12-20 06:05:13 +0000323 def getresponse(self):
324 return MockHTTPResponse(MockFile(), {}, 200, "OK")
325
Victor Stinnerc74a6ba2011-06-17 14:06:27 +0200326 def close(self):
327 pass
328
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000329class MockHandler:
Georg Brandlfa42bd72006-04-30 07:06:11 +0000330 # useful for testing handler machinery
331 # see add_ordered_mock_handlers() docstring
Georg Brandl720096a2006-04-02 20:45:34 +0000332 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000333 def __init__(self, methods):
334 self._define_methods(methods)
335 def _define_methods(self, methods):
336 for spec in methods:
337 if len(spec) == 2: name, action = spec
338 else: name, action = spec, None
339 meth = FakeMethod(name, action, self.handle)
340 setattr(self.__class__, name, meth)
341 def handle(self, fn_name, action, *args, **kwds):
342 self.parent.calls.append((self, fn_name, args, kwds))
343 if action is None:
344 return None
345 elif action == "return self":
346 return self
347 elif action == "return response":
348 res = MockResponse(200, "OK", {}, "")
349 return res
350 elif action == "return request":
351 return Request("http://blah/")
352 elif action.startswith("error"):
353 code = action[action.rfind(" ")+1:]
354 try:
355 code = int(code)
356 except ValueError:
357 pass
358 res = MockResponse(200, "OK", {}, "")
359 return self.parent.error("http", args[0], res, code, "", {})
360 elif action == "raise":
361 raise urllib2.URLError("blah")
362 assert False
363 def close(self): pass
364 def add_parent(self, parent):
365 self.parent = parent
366 self.parent.calls = []
367 def __lt__(self, other):
368 if not hasattr(other, "handler_order"):
369 # No handler_order, leave in original order. Yuck.
370 return True
371 return self.handler_order < other.handler_order
372
373def add_ordered_mock_handlers(opener, meth_spec):
374 """Create MockHandlers and add them to an OpenerDirector.
375
376 meth_spec: list of lists of tuples and strings defining methods to define
377 on handlers. eg:
378
379 [["http_error", "ftp_open"], ["http_open"]]
380
381 defines methods .http_error() and .ftp_open() on one handler, and
382 .http_open() on another. These methods just record their arguments and
383 return None. Using a tuple instead of a string causes the method to
384 perform some action (see MockHandler.handle()), eg:
385
386 [["http_error"], [("http_open", "return request")]]
387
388 defines .http_error() on one handler (which simply returns None), and
389 .http_open() on another handler, which returns a Request object.
390
391 """
392 handlers = []
393 count = 0
394 for meths in meth_spec:
395 class MockHandlerSubclass(MockHandler): pass
396 h = MockHandlerSubclass(meths)
Georg Brandl720096a2006-04-02 20:45:34 +0000397 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000398 h.add_parent(opener)
399 count = count + 1
400 handlers.append(h)
401 opener.add_handler(h)
402 return handlers
403
Georg Brandlfa42bd72006-04-30 07:06:11 +0000404def build_test_opener(*handler_instances):
405 opener = OpenerDirector()
406 for h in handler_instances:
407 opener.add_handler(h)
408 return opener
409
410class MockHTTPHandler(urllib2.BaseHandler):
411 # useful for testing redirections and auth
412 # sends supplied headers and code as first response
413 # sends 200 OK as second response
414 def __init__(self, code, headers):
415 self.code = code
416 self.headers = headers
417 self.reset()
418 def reset(self):
419 self._count = 0
420 self.requests = []
421 def http_open(self, req):
422 import mimetools, httplib, copy
423 from StringIO import StringIO
424 self.requests.append(copy.deepcopy(req))
425 if self._count == 0:
426 self._count = self._count + 1
427 name = httplib.responses[self.code]
428 msg = mimetools.Message(StringIO(self.headers))
429 return self.parent.error(
430 "http", req, MockFile(), self.code, name, msg)
431 else:
432 self.req = req
433 msg = mimetools.Message(StringIO("\r\n\r\n"))
434 return MockResponse(200, "OK", msg, "", req.get_full_url())
435
Senthil Kumaran7713acf2009-12-20 06:05:13 +0000436class MockHTTPSHandler(urllib2.AbstractHTTPHandler):
437 # Useful for testing the Proxy-Authorization request by verifying the
438 # properties of httpcon
Benjamin Peterson32935932009-12-24 01:09:53 +0000439
440 def __init__(self):
441 urllib2.AbstractHTTPHandler.__init__(self)
442 self.httpconn = MockHTTPClass()
443
Senthil Kumaran7713acf2009-12-20 06:05:13 +0000444 def https_open(self, req):
445 return self.do_open(self.httpconn, req)
446
Georg Brandlfa42bd72006-04-30 07:06:11 +0000447class MockPasswordManager:
448 def add_password(self, realm, uri, user, password):
449 self.realm = realm
450 self.url = uri
451 self.user = user
452 self.password = password
453 def find_user_password(self, realm, authuri):
454 self.target_realm = realm
455 self.target_url = authuri
456 return self.user, self.password
457
458
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000459class OpenerDirectorTests(unittest.TestCase):
460
Georg Brandlf91149e2007-07-12 08:05:45 +0000461 def test_add_non_handler(self):
462 class NonHandler(object):
463 pass
464 self.assertRaises(TypeError,
465 OpenerDirector().add_handler, NonHandler())
466
Georg Brandl261e2512006-05-29 20:52:54 +0000467 def test_badly_named_methods(self):
468 # test work-around for three methods that accidentally follow the
469 # naming conventions for handler methods
470 # (*_open() / *_request() / *_response())
471
472 # These used to call the accidentally-named methods, causing a
473 # TypeError in real code; here, returning self from these mock
474 # methods would either cause no exception, or AttributeError.
475
476 from urllib2 import URLError
477
478 o = OpenerDirector()
479 meth_spec = [
480 [("do_open", "return self"), ("proxy_open", "return self")],
481 [("redirect_request", "return self")],
482 ]
483 handlers = add_ordered_mock_handlers(o, meth_spec)
484 o.add_handler(urllib2.UnknownHandler())
485 for scheme in "do", "proxy", "redirect":
486 self.assertRaises(URLError, o.open, scheme+"://example.com/")
487
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000488 def test_handled(self):
489 # handler returning non-None means no more handlers will be called
490 o = OpenerDirector()
491 meth_spec = [
492 ["http_open", "ftp_open", "http_error_302"],
493 ["ftp_open"],
494 [("http_open", "return self")],
495 [("http_open", "return self")],
496 ]
497 handlers = add_ordered_mock_handlers(o, meth_spec)
498
499 req = Request("http://example.com/")
500 r = o.open(req)
501 # Second .http_open() gets called, third doesn't, since second returned
502 # non-None. Handlers without .http_open() never get any methods called
503 # on them.
504 # In fact, second mock handler defining .http_open() returns self
505 # (instead of response), which becomes the OpenerDirector's return
506 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000507 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000508 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
509 for expected, got in zip(calls, o.calls):
510 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000511 self.assertEqual((handler, name), expected)
512 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000513
514 def test_handler_order(self):
515 o = OpenerDirector()
516 handlers = []
517 for meths, handler_order in [
518 ([("http_open", "return self")], 500),
519 (["http_open"], 0),
520 ]:
521 class MockHandlerSubclass(MockHandler): pass
522 h = MockHandlerSubclass(meths)
523 h.handler_order = handler_order
524 handlers.append(h)
525 o.add_handler(h)
526
527 r = o.open("http://example.com/")
528 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000529 self.assertEqual(o.calls[0][0], handlers[1])
530 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000531
532 def test_raise(self):
533 # raising URLError stops processing of request
534 o = OpenerDirector()
535 meth_spec = [
536 [("http_open", "raise")],
537 [("http_open", "return self")],
538 ]
539 handlers = add_ordered_mock_handlers(o, meth_spec)
540
541 req = Request("http://example.com/")
542 self.assertRaises(urllib2.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000543 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000544
545## def test_error(self):
546## # XXX this doesn't actually seem to be used in standard library,
547## # but should really be tested anyway...
548
549 def test_http_error(self):
550 # XXX http_error_default
551 # http errors are a special case
552 o = OpenerDirector()
553 meth_spec = [
554 [("http_open", "error 302")],
555 [("http_error_400", "raise"), "http_open"],
556 [("http_error_302", "return response"), "http_error_303",
557 "http_error"],
558 [("http_error_302")],
559 ]
560 handlers = add_ordered_mock_handlers(o, meth_spec)
561
562 class Unknown:
563 def __eq__(self, other): return True
564
565 req = Request("http://example.com/")
566 r = o.open(req)
567 assert len(o.calls) == 2
568 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000569 (handlers[2], "http_error_302",
570 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000571 for expected, got in zip(calls, o.calls):
572 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000573 self.assertEqual((handler, method_name), got[:2])
574 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000575
576 def test_processors(self):
577 # *_request / *_response methods get called appropriately
578 o = OpenerDirector()
579 meth_spec = [
580 [("http_request", "return request"),
581 ("http_response", "return response")],
582 [("http_request", "return request"),
583 ("http_response", "return response")],
584 ]
585 handlers = add_ordered_mock_handlers(o, meth_spec)
586
587 req = Request("http://example.com/")
588 r = o.open(req)
589 # processor methods are called on *all* handlers that define them,
590 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000591 calls = [
592 (handlers[0], "http_request"), (handlers[1], "http_request"),
593 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000594
595 for i, (handler, name, args, kwds) in enumerate(o.calls):
596 if i < 2:
597 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000598 self.assertEqual((handler, name), calls[i])
599 self.assertEqual(len(args), 1)
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000600 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000601 else:
602 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000603 self.assertEqual((handler, name), calls[i])
604 self.assertEqual(len(args), 2)
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000605 self.assertIsInstance(args[0], Request)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000606 # response from opener.open is None, because there's no
607 # handler that defines http_open to handle it
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200608 if args[1] is not None:
609 self.assertIsInstance(args[1], MockResponse)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000610
611
Tim Peters58eb11c2004-01-18 20:29:55 +0000612def sanepathname2url(path):
613 import urllib
614 urlpath = urllib.pathname2url(path)
615 if os.name == "nt" and urlpath.startswith("///"):
616 urlpath = urlpath[2:]
617 # XXX don't ask me about the mac...
618 return urlpath
619
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000620class HandlerTests(unittest.TestCase):
621
622 def test_ftp(self):
623 class MockFTPWrapper:
624 def __init__(self, data): self.data = data
625 def retrfile(self, filename, filetype):
626 self.filename, self.filetype = filename, filetype
627 return StringIO.StringIO(self.data), len(self.data)
Nadeem Vawdab42c53e2011-07-23 15:51:16 +0200628 def close(self): pass
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000629
630 class NullFTPHandler(urllib2.FTPHandler):
631 def __init__(self, data): self.data = data
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000632 def connect_ftp(self, user, passwd, host, port, dirs,
633 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000634 self.user, self.passwd = user, passwd
635 self.host, self.port = host, port
636 self.dirs = dirs
637 self.ftpwrapper = MockFTPWrapper(self.data)
638 return self.ftpwrapper
639
Facundo Batista4f1b1ed2008-05-29 16:39:26 +0000640 import ftplib
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000641 data = "rheum rhaponicum"
642 h = NullFTPHandler(data)
643 o = h.parent = MockOpener()
644
Senthil Kumaran9fce5512010-11-20 11:24:08 +0000645 for url, host, port, user, passwd, type_, dirs, filename, mimetype in [
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000646 ("ftp://localhost/foo/bar/baz.html",
Senthil Kumaran9fce5512010-11-20 11:24:08 +0000647 "localhost", ftplib.FTP_PORT, "", "", "I",
648 ["foo", "bar"], "baz.html", "text/html"),
649 ("ftp://parrot@localhost/foo/bar/baz.html",
650 "localhost", ftplib.FTP_PORT, "parrot", "", "I",
651 ["foo", "bar"], "baz.html", "text/html"),
652 ("ftp://%25parrot@localhost/foo/bar/baz.html",
653 "localhost", ftplib.FTP_PORT, "%parrot", "", "I",
654 ["foo", "bar"], "baz.html", "text/html"),
655 ("ftp://%2542parrot@localhost/foo/bar/baz.html",
656 "localhost", ftplib.FTP_PORT, "%42parrot", "", "I",
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000657 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000658 ("ftp://localhost:80/foo/bar/",
Senthil Kumaran9fce5512010-11-20 11:24:08 +0000659 "localhost", 80, "", "", "D",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000660 ["foo", "bar"], "", None),
661 ("ftp://localhost/baz.gif;type=a",
Senthil Kumaran9fce5512010-11-20 11:24:08 +0000662 "localhost", ftplib.FTP_PORT, "", "", "A",
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000663 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000664 ]:
Facundo Batista10951d52007-06-06 17:15:23 +0000665 req = Request(url)
666 req.timeout = None
667 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000668 # ftp authentication not yet implemented by FTPHandler
Senthil Kumaran9fce5512010-11-20 11:24:08 +0000669 self.assertEqual(h.user, user)
670 self.assertEqual(h.passwd, passwd)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000671 self.assertEqual(h.host, socket.gethostbyname(host))
672 self.assertEqual(h.port, port)
673 self.assertEqual(h.dirs, dirs)
674 self.assertEqual(h.ftpwrapper.filename, filename)
675 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000676 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000677 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000678 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000679
680 def test_file(self):
Christian Heimesc5f05e42008-02-23 17:40:11 +0000681 import rfc822, socket
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000682 h = urllib2.FileHandler()
683 o = h.parent = MockOpener()
684
Tim Peters58eb11c2004-01-18 20:29:55 +0000685 TESTFN = test_support.TESTFN
686 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000687 towrite = "hello, world\n"
Georg Brandldd2245f2006-03-31 17:18:06 +0000688 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000689 "file://localhost%s" % urlpath,
690 "file://%s" % urlpath,
691 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Georg Brandldd2245f2006-03-31 17:18:06 +0000692 ]
693 try:
Tim Peters480725d2006-04-03 02:46:44 +0000694 localaddr = socket.gethostbyname(socket.gethostname())
Georg Brandldd2245f2006-03-31 17:18:06 +0000695 except socket.gaierror:
696 localaddr = ''
697 if localaddr:
698 urls.append("file://%s%s" % (localaddr, urlpath))
Tim Peters480725d2006-04-03 02:46:44 +0000699
Georg Brandldd2245f2006-03-31 17:18:06 +0000700 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000701 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000702 try:
703 try:
704 f.write(towrite)
705 finally:
706 f.close()
707
708 r = h.file_open(Request(url))
709 try:
710 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000711 headers = r.info()
Senthil Kumaran6057ba12010-05-08 03:11:50 +0000712 respurl = r.geturl()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000713 finally:
714 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000715 stats = os.stat(TESTFN)
716 modified = rfc822.formatdate(stats.st_mtime)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000717 finally:
718 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000719 self.assertEqual(data, towrite)
720 self.assertEqual(headers["Content-type"], "text/plain")
721 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000722 self.assertEqual(headers["Last-modified"], modified)
Senthil Kumaran6057ba12010-05-08 03:11:50 +0000723 self.assertEqual(respurl, url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000724
725 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000726 "file://localhost:80%s" % urlpath,
Georg Brandlceede5c2007-03-13 08:14:27 +0000727 "file:///file_does_not_exist.txt",
728 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
729 os.getcwd(), TESTFN),
730 "file://somerandomhost.ontheinternet.com%s/%s" %
731 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000732 ]:
733 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000734 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000735 try:
736 f.write(towrite)
737 finally:
738 f.close()
739
740 self.assertRaises(urllib2.URLError,
741 h.file_open, Request(url))
742 finally:
743 os.remove(TESTFN)
744
745 h = urllib2.FileHandler()
746 o = h.parent = MockOpener()
747 # XXXX why does // mean ftp (and /// mean not ftp!), and where
748 # is file: scheme specified? I think this is really a bug, and
749 # what was intended was to distinguish between URLs like:
750 # file:/blah.txt (a file)
751 # file://localhost/blah.txt (a file)
752 # file:///blah.txt (a file)
753 # file://ftp.example.com/blah.txt (an ftp URL)
754 for url, ftp in [
755 ("file://ftp.example.com//foo.txt", True),
756 ("file://ftp.example.com///foo.txt", False),
757# XXXX bug: fails with OSError, should be URLError
758 ("file://ftp.example.com/foo.txt", False),
Senthil Kumaran87ed31a2010-07-11 03:18:51 +0000759 ("file://somehost//foo/something.txt", True),
760 ("file://localhost//foo/something.txt", False),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000761 ]:
762 req = Request(url)
763 try:
764 h.file_open(req)
765 # XXXX remove OSError when bug fixed
766 except (urllib2.URLError, OSError):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000767 self.assertTrue(not ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000768 else:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000769 self.assertTrue(o.req is req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000770 self.assertEqual(req.type, "ftp")
Benjamin Peterson98104272011-01-12 19:27:17 +0000771 self.assertEqual(req.type == "ftp", ftp)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000772
773 def test_http(self):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000774
775 h = urllib2.AbstractHTTPHandler()
776 o = h.parent = MockOpener()
777
778 url = "http://example.com/"
779 for method, data in [("GET", None), ("POST", "blah")]:
780 req = Request(url, data, {"Foo": "bar"})
Facundo Batista10951d52007-06-06 17:15:23 +0000781 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000782 req.add_unredirected_header("Spam", "eggs")
783 http = MockHTTPClass()
784 r = h.do_open(http, req)
785
786 # result attributes
787 r.read; r.readline # wrapped MockFile methods
788 r.info; r.geturl # addinfourl methods
789 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
790 hdrs = r.info()
791 hdrs.get; hdrs.has_key # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000792 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000793
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000794 self.assertEqual(http.host, "example.com")
795 self.assertEqual(http.level, 0)
796 self.assertEqual(http.method, method)
797 self.assertEqual(http.selector, "/")
798 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000799 [("Connection", "close"),
800 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000801 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000802
803 # check socket.error converted to URLError
804 http.raise_on_endheaders = True
805 self.assertRaises(urllib2.URLError, h.do_open, http, req)
806
807 # check adding of standard headers
808 o.addheaders = [("Spam", "eggs")]
809 for data in "", None: # POST, GET
810 req = Request("http://example.com/", data)
811 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000812 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000813 if data is None: # GET
Ezio Melottiaa980582010-01-23 23:04:36 +0000814 self.assertNotIn("Content-length", req.unredirected_hdrs)
815 self.assertNotIn("Content-type", req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000816 else: # POST
Georg Brandl8c036cc2006-08-20 13:15:39 +0000817 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
818 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000819 "application/x-www-form-urlencoded")
820 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000821 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
822 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000823
824 # don't clobber existing headers
825 req.add_unredirected_header("Content-length", "foo")
826 req.add_unredirected_header("Content-type", "bar")
827 req.add_unredirected_header("Host", "baz")
828 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000829 newreq = h.do_request_(req)
Georg Brandl8c036cc2006-08-20 13:15:39 +0000830 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
831 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000832 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
833 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000834
Facundo Batistaeb90b782008-08-16 14:44:07 +0000835 def test_http_doubleslash(self):
836 # Checks that the presence of an unnecessary double slash in a url doesn't break anything
837 # Previously, a double slash directly after the host could cause incorrect parsing of the url
838 h = urllib2.AbstractHTTPHandler()
839 o = h.parent = MockOpener()
840
841 data = ""
842 ds_urls = [
843 "http://example.com/foo/bar/baz.html",
844 "http://example.com//foo/bar/baz.html",
845 "http://example.com/foo//bar/baz.html",
846 "http://example.com/foo/bar//baz.html",
847 ]
848
849 for ds_url in ds_urls:
850 ds_req = Request(ds_url, data)
851
852 # Check whether host is determined correctly if there is no proxy
853 np_ds_req = h.do_request_(ds_req)
854 self.assertEqual(np_ds_req.unredirected_hdrs["Host"],"example.com")
855
856 # Check whether host is determined correctly if there is a proxy
857 ds_req.set_proxy("someproxy:3128",None)
858 p_ds_req = h.do_request_(ds_req)
859 self.assertEqual(p_ds_req.unredirected_hdrs["Host"],"example.com")
860
Senthil Kumaran0b7cac12010-11-22 05:04:33 +0000861 def test_fixpath_in_weirdurls(self):
862 # Issue4493: urllib2 to supply '/' when to urls where path does not
863 # start with'/'
864
865 h = urllib2.AbstractHTTPHandler()
866 o = h.parent = MockOpener()
867
868 weird_url = 'http://www.python.org?getspam'
869 req = Request(weird_url)
870 newreq = h.do_request_(req)
871 self.assertEqual(newreq.get_host(),'www.python.org')
872 self.assertEqual(newreq.get_selector(),'/?getspam')
873
874 url_without_path = 'http://www.python.org'
875 req = Request(url_without_path)
876 newreq = h.do_request_(req)
877 self.assertEqual(newreq.get_host(),'www.python.org')
878 self.assertEqual(newreq.get_selector(),'')
879
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000880 def test_errors(self):
881 h = urllib2.HTTPErrorProcessor()
882 o = h.parent = MockOpener()
883
884 url = "http://example.com/"
885 req = Request(url)
Facundo Batista9fab9f12007-04-23 17:08:31 +0000886 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000887 r = MockResponse(200, "OK", {}, "", url)
888 newr = h.http_response(req, r)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000889 self.assertTrue(r is newr)
890 self.assertTrue(not hasattr(o, "proto")) # o.error not called
Facundo Batista9fab9f12007-04-23 17:08:31 +0000891 r = MockResponse(202, "Accepted", {}, "", url)
892 newr = h.http_response(req, r)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000893 self.assertTrue(r is newr)
894 self.assertTrue(not hasattr(o, "proto")) # o.error not called
Facundo Batista9fab9f12007-04-23 17:08:31 +0000895 r = MockResponse(206, "Partial content", {}, "", url)
896 newr = h.http_response(req, r)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000897 self.assertTrue(r is newr)
898 self.assertTrue(not hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000899 # anything else calls o.error (and MockOpener returns None, here)
Facundo Batista9fab9f12007-04-23 17:08:31 +0000900 r = MockResponse(502, "Bad gateway", {}, "", url)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000901 self.assertTrue(h.http_response(req, r) is None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000902 self.assertEqual(o.proto, "http") # o.error called
Facundo Batista9fab9f12007-04-23 17:08:31 +0000903 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000904
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000905 def test_cookies(self):
906 cj = MockCookieJar()
907 h = urllib2.HTTPCookieProcessor(cj)
908 o = h.parent = MockOpener()
909
910 req = Request("http://example.com/")
911 r = MockResponse(200, "OK", {}, "")
912 newreq = h.http_request(req)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000913 self.assertTrue(cj.ach_req is req is newreq)
Ezio Melotti2623a372010-11-21 13:34:58 +0000914 self.assertEqual(req.get_origin_req_host(), "example.com")
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000915 self.assertTrue(not req.is_unverifiable())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000916 newr = h.http_response(req, r)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000917 self.assertTrue(cj.ec_req is req)
918 self.assertTrue(cj.ec_r is r is newr)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000919
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000920 def test_redirect(self):
921 from_url = "http://example.com/a.html"
922 to_url = "http://example.com/b.html"
923 h = urllib2.HTTPRedirectHandler()
924 o = h.parent = MockOpener()
925
926 # ordinary redirect behaviour
927 for code in 301, 302, 303, 307:
928 for data in None, "blah\nblah\n":
929 method = getattr(h, "http_error_%s" % code)
930 req = Request(from_url, data)
931 req.add_header("Nonsense", "viking=withhold")
Senthil Kumaran5fee4602009-07-19 02:43:43 +0000932 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Facundo Batista86371d62008-02-07 19:06:52 +0000933 if data is not None:
934 req.add_header("Content-Length", str(len(data)))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000935 req.add_unredirected_header("Spam", "spam")
936 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000937 method(req, MockFile(), code, "Blah",
938 MockHeaders({"location": to_url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000939 except urllib2.HTTPError:
940 # 307 in response to POST requires user OK
Serhiy Storchaka528bed82014-02-08 14:49:55 +0200941 self.assertEqual(code, 307)
942 self.assertIsNotNone(data)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000943 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000944 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000945 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000946 except AttributeError:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000947 self.assertTrue(not o.req.has_data())
Facundo Batista86371d62008-02-07 19:06:52 +0000948
949 # now it's a GET, there should not be headers regarding content
950 # (possibly dragged from before being a POST)
951 headers = [x.lower() for x in o.req.headers]
Ezio Melottiaa980582010-01-23 23:04:36 +0000952 self.assertNotIn("content-length", headers)
953 self.assertNotIn("content-type", headers)
Facundo Batista86371d62008-02-07 19:06:52 +0000954
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000955 self.assertEqual(o.req.headers["Nonsense"],
956 "viking=withhold")
Ezio Melottiaa980582010-01-23 23:04:36 +0000957 self.assertNotIn("Spam", o.req.headers)
958 self.assertNotIn("Spam", o.req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000959
960 # loop detection
961 req = Request(from_url)
Senthil Kumaran5fee4602009-07-19 02:43:43 +0000962 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000963 def redirect(h, req, url=to_url):
964 h.http_error_302(req, MockFile(), 302, "Blah",
965 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000966 # Note that the *original* request shares the same record of
967 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000968
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000969 # detect infinite loop redirect of a URL to itself
970 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000971 count = 0
Senthil Kumaran5fee4602009-07-19 02:43:43 +0000972 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000973 try:
974 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000975 redirect(h, req, "http://example.com/")
976 count = count + 1
977 except urllib2.HTTPError:
978 # don't stop until max_repeats, because cookies may introduce state
979 self.assertEqual(count, urllib2.HTTPRedirectHandler.max_repeats)
980
981 # detect endless non-repeating chain of redirects
982 req = Request(from_url, origin_req_host="example.com")
983 count = 0
Senthil Kumaran5fee4602009-07-19 02:43:43 +0000984 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000985 try:
986 while 1:
987 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000988 count = count + 1
989 except urllib2.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000990 self.assertEqual(count,
991 urllib2.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000992
guido@google.comf1509302011-03-28 13:47:01 -0700993 def test_invalid_redirect(self):
994 from_url = "http://example.com/a.html"
995 valid_schemes = ['http', 'https', 'ftp']
996 invalid_schemes = ['file', 'imap', 'ldap']
997 schemeless_url = "example.com/b.html"
998 h = urllib2.HTTPRedirectHandler()
999 o = h.parent = MockOpener()
1000 req = Request(from_url)
guido@google.com9a9fdfa2011-03-29 10:48:23 -07001001 req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
guido@google.comf1509302011-03-28 13:47:01 -07001002
1003 for scheme in invalid_schemes:
1004 invalid_url = scheme + '://' + schemeless_url
1005 self.assertRaises(urllib2.HTTPError, h.http_error_302,
1006 req, MockFile(), 302, "Security Loophole",
1007 MockHeaders({"location": invalid_url}))
1008
1009 for scheme in valid_schemes:
1010 valid_url = scheme + '://' + schemeless_url
1011 h.http_error_302(req, MockFile(), 302, "That's fine",
1012 MockHeaders({"location": valid_url}))
1013 self.assertEqual(o.req.get_full_url(), valid_url)
1014
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001015 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001016 # cookies shouldn't leak into redirected requests
1017 from cookielib import CookieJar
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001018
Neal Norwitzb902f4e2006-04-03 04:45:34 +00001019 from test.test_cookielib import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001020
1021 cj = CookieJar()
1022 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Georg Brandlfa42bd72006-04-30 07:06:11 +00001023 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
1024 hdeh = urllib2.HTTPDefaultErrorHandler()
1025 hrh = urllib2.HTTPRedirectHandler()
1026 cp = urllib2.HTTPCookieProcessor(cj)
1027 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001028 o.open("http://www.example.com/")
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001029 self.assertTrue(not hh.req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001030
Senthil Kumaran49c44082011-04-13 07:31:45 +08001031 def test_redirect_fragment(self):
1032 redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
1033 hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
1034 hdeh = urllib2.HTTPDefaultErrorHandler()
1035 hrh = urllib2.HTTPRedirectHandler()
1036 o = build_test_opener(hh, hdeh, hrh)
1037 fp = o.open('http://www.example.com')
1038 self.assertEqual(fp.geturl(), redirected_url.strip())
1039
Georg Brandl720096a2006-04-02 20:45:34 +00001040 def test_proxy(self):
1041 o = OpenerDirector()
1042 ph = urllib2.ProxyHandler(dict(http="proxy.example.com:3128"))
1043 o.add_handler(ph)
1044 meth_spec = [
1045 [("http_open", "return response")]
1046 ]
1047 handlers = add_ordered_mock_handlers(o, meth_spec)
1048
1049 req = Request("http://acme.example.com/")
1050 self.assertEqual(req.get_host(), "acme.example.com")
1051 r = o.open(req)
1052 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1053
1054 self.assertEqual([(handlers[0], "http_open")],
1055 [tup[0:2] for tup in o.calls])
1056
Senthil Kumaran27468662009-10-11 02:00:07 +00001057 def test_proxy_no_proxy(self):
1058 os.environ['no_proxy'] = 'python.org'
1059 o = OpenerDirector()
1060 ph = urllib2.ProxyHandler(dict(http="proxy.example.com"))
1061 o.add_handler(ph)
1062 req = Request("http://www.perl.org/")
1063 self.assertEqual(req.get_host(), "www.perl.org")
1064 r = o.open(req)
1065 self.assertEqual(req.get_host(), "proxy.example.com")
1066 req = Request("http://www.python.org")
1067 self.assertEqual(req.get_host(), "www.python.org")
1068 r = o.open(req)
1069 self.assertEqual(req.get_host(), "www.python.org")
1070 del os.environ['no_proxy']
1071
1072
Senthil Kumarane266f252009-05-24 09:14:50 +00001073 def test_proxy_https(self):
1074 o = OpenerDirector()
1075 ph = urllib2.ProxyHandler(dict(https='proxy.example.com:3128'))
1076 o.add_handler(ph)
1077 meth_spec = [
1078 [("https_open","return response")]
1079 ]
1080 handlers = add_ordered_mock_handlers(o, meth_spec)
1081 req = Request("https://www.example.com/")
1082 self.assertEqual(req.get_host(), "www.example.com")
1083 r = o.open(req)
1084 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1085 self.assertEqual([(handlers[0], "https_open")],
1086 [tup[0:2] for tup in o.calls])
1087
Senthil Kumaran7713acf2009-12-20 06:05:13 +00001088 def test_proxy_https_proxy_authorization(self):
1089 o = OpenerDirector()
1090 ph = urllib2.ProxyHandler(dict(https='proxy.example.com:3128'))
1091 o.add_handler(ph)
1092 https_handler = MockHTTPSHandler()
1093 o.add_handler(https_handler)
1094 req = Request("https://www.example.com/")
1095 req.add_header("Proxy-Authorization","FooBar")
1096 req.add_header("User-Agent","Grail")
1097 self.assertEqual(req.get_host(), "www.example.com")
1098 self.assertIsNone(req._tunnel_host)
1099 r = o.open(req)
1100 # Verify Proxy-Authorization gets tunneled to request.
1101 # httpsconn req_headers do not have the Proxy-Authorization header but
1102 # the req will have.
Ezio Melottiaa980582010-01-23 23:04:36 +00001103 self.assertNotIn(("Proxy-Authorization","FooBar"),
Senthil Kumaran7713acf2009-12-20 06:05:13 +00001104 https_handler.httpconn.req_headers)
Ezio Melottiaa980582010-01-23 23:04:36 +00001105 self.assertIn(("User-Agent","Grail"),
1106 https_handler.httpconn.req_headers)
Senthil Kumaran7713acf2009-12-20 06:05:13 +00001107 self.assertIsNotNone(req._tunnel_host)
1108 self.assertEqual(req.get_host(), "proxy.example.com:3128")
1109 self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
1110
Georg Brandl33124322008-03-21 19:54:00 +00001111 def test_basic_auth(self, quote_char='"'):
Georg Brandlfa42bd72006-04-30 07:06:11 +00001112 opener = OpenerDirector()
1113 password_manager = MockPasswordManager()
1114 auth_handler = urllib2.HTTPBasicAuthHandler(password_manager)
1115 realm = "ACME Widget Store"
1116 http_handler = MockHTTPHandler(
Georg Brandl33124322008-03-21 19:54:00 +00001117 401, 'WWW-Authenticate: Basic realm=%s%s%s\r\n\r\n' %
1118 (quote_char, realm, quote_char) )
Georg Brandl261e2512006-05-29 20:52:54 +00001119 opener.add_handler(auth_handler)
1120 opener.add_handler(http_handler)
Georg Brandlfa42bd72006-04-30 07:06:11 +00001121 self._test_basic_auth(opener, auth_handler, "Authorization",
1122 realm, http_handler, password_manager,
1123 "http://acme.example.com/protected",
Senthil Kumaranb0d85fd2012-05-15 23:59:19 +08001124 "http://acme.example.com/protected"
1125 )
Georg Brandlfa42bd72006-04-30 07:06:11 +00001126
Georg Brandl33124322008-03-21 19:54:00 +00001127 def test_basic_auth_with_single_quoted_realm(self):
1128 self.test_basic_auth(quote_char="'")
1129
Senthil Kumaran6a2a6c22012-05-15 22:24:10 +08001130 def test_basic_auth_with_unquoted_realm(self):
1131 opener = OpenerDirector()
1132 password_manager = MockPasswordManager()
1133 auth_handler = urllib2.HTTPBasicAuthHandler(password_manager)
1134 realm = "ACME Widget Store"
1135 http_handler = MockHTTPHandler(
1136 401, 'WWW-Authenticate: Basic realm=%s\r\n\r\n' % realm)
1137 opener.add_handler(auth_handler)
1138 opener.add_handler(http_handler)
Senthil Kumaranb0d85fd2012-05-15 23:59:19 +08001139 msg = "Basic Auth Realm was unquoted"
1140 with test_support.check_warnings((msg, UserWarning)):
1141 self._test_basic_auth(opener, auth_handler, "Authorization",
1142 realm, http_handler, password_manager,
1143 "http://acme.example.com/protected",
1144 "http://acme.example.com/protected"
1145 )
Senthil Kumaran6a2a6c22012-05-15 22:24:10 +08001146
1147
Georg Brandlfa42bd72006-04-30 07:06:11 +00001148 def test_proxy_basic_auth(self):
1149 opener = OpenerDirector()
1150 ph = urllib2.ProxyHandler(dict(http="proxy.example.com:3128"))
1151 opener.add_handler(ph)
1152 password_manager = MockPasswordManager()
1153 auth_handler = urllib2.ProxyBasicAuthHandler(password_manager)
1154 realm = "ACME Networks"
1155 http_handler = MockHTTPHandler(
1156 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Georg Brandl261e2512006-05-29 20:52:54 +00001157 opener.add_handler(auth_handler)
1158 opener.add_handler(http_handler)
Georg Brandl8c036cc2006-08-20 13:15:39 +00001159 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Georg Brandlfa42bd72006-04-30 07:06:11 +00001160 realm, http_handler, password_manager,
1161 "http://acme.example.com:3128/protected",
1162 "proxy.example.com:3128",
1163 )
1164
Georg Brandlb5f2e5c2006-05-08 17:36:08 +00001165 def test_basic_and_digest_auth_handlers(self):
Andrew Svetlovbacf1bf2012-12-19 22:49:01 +02001166 # HTTPDigestAuthHandler raised an exception if it couldn't handle a 40*
Georg Brandlb5f2e5c2006-05-08 17:36:08 +00001167 # response (http://python.org/sf/1479302), where it should instead
1168 # return None to allow another handler (especially
1169 # HTTPBasicAuthHandler) to handle the response.
Georg Brandl261e2512006-05-29 20:52:54 +00001170
1171 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
1172 # try digest first (since it's the strongest auth scheme), so we record
1173 # order of calls here to check digest comes first:
1174 class RecordingOpenerDirector(OpenerDirector):
1175 def __init__(self):
1176 OpenerDirector.__init__(self)
1177 self.recorded = []
1178 def record(self, info):
1179 self.recorded.append(info)
Georg Brandlb5f2e5c2006-05-08 17:36:08 +00001180 class TestDigestAuthHandler(urllib2.HTTPDigestAuthHandler):
Georg Brandl261e2512006-05-29 20:52:54 +00001181 def http_error_401(self, *args, **kwds):
1182 self.parent.record("digest")
1183 urllib2.HTTPDigestAuthHandler.http_error_401(self,
1184 *args, **kwds)
1185 class TestBasicAuthHandler(urllib2.HTTPBasicAuthHandler):
1186 def http_error_401(self, *args, **kwds):
1187 self.parent.record("basic")
1188 urllib2.HTTPBasicAuthHandler.http_error_401(self,
1189 *args, **kwds)
1190
1191 opener = RecordingOpenerDirector()
Georg Brandlb5f2e5c2006-05-08 17:36:08 +00001192 password_manager = MockPasswordManager()
1193 digest_handler = TestDigestAuthHandler(password_manager)
Georg Brandl261e2512006-05-29 20:52:54 +00001194 basic_handler = TestBasicAuthHandler(password_manager)
Georg Brandlb5f2e5c2006-05-08 17:36:08 +00001195 realm = "ACME Networks"
1196 http_handler = MockHTTPHandler(
1197 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Georg Brandl261e2512006-05-29 20:52:54 +00001198 opener.add_handler(basic_handler)
1199 opener.add_handler(digest_handler)
1200 opener.add_handler(http_handler)
1201
1202 # check basic auth isn't blocked by digest handler failing
Georg Brandlb5f2e5c2006-05-08 17:36:08 +00001203 self._test_basic_auth(opener, basic_handler, "Authorization",
1204 realm, http_handler, password_manager,
1205 "http://acme.example.com/protected",
1206 "http://acme.example.com/protected",
1207 )
Georg Brandl261e2512006-05-29 20:52:54 +00001208 # check digest was tried before basic (twice, because
1209 # _test_basic_auth called .open() twice)
1210 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Georg Brandlb5f2e5c2006-05-08 17:36:08 +00001211
Georg Brandlfa42bd72006-04-30 07:06:11 +00001212 def _test_basic_auth(self, opener, auth_handler, auth_header,
1213 realm, http_handler, password_manager,
1214 request_url, protected_url):
Christian Heimesc5f05e42008-02-23 17:40:11 +00001215 import base64
Georg Brandlfa42bd72006-04-30 07:06:11 +00001216 user, password = "wile", "coyote"
Georg Brandlfa42bd72006-04-30 07:06:11 +00001217
1218 # .add_password() fed through to password manager
1219 auth_handler.add_password(realm, request_url, user, password)
1220 self.assertEqual(realm, password_manager.realm)
1221 self.assertEqual(request_url, password_manager.url)
1222 self.assertEqual(user, password_manager.user)
1223 self.assertEqual(password, password_manager.password)
1224
1225 r = opener.open(request_url)
1226
1227 # should have asked the password manager for the username/password
1228 self.assertEqual(password_manager.target_realm, realm)
1229 self.assertEqual(password_manager.target_url, protected_url)
1230
1231 # expect one request without authorization, then one with
1232 self.assertEqual(len(http_handler.requests), 2)
1233 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1234 userpass = '%s:%s' % (user, password)
1235 auth_hdr_value = 'Basic '+base64.encodestring(userpass).strip()
1236 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1237 auth_hdr_value)
Senthil Kumaran8526adf2010-02-24 16:45:46 +00001238 self.assertEqual(http_handler.requests[1].unredirected_hdrs[auth_header],
1239 auth_hdr_value)
Georg Brandlfa42bd72006-04-30 07:06:11 +00001240 # if the password manager can't find a password, the handler won't
1241 # handle the HTTP auth error
1242 password_manager.user = password_manager.password = None
1243 http_handler.reset()
1244 r = opener.open(request_url)
1245 self.assertEqual(len(http_handler.requests), 1)
1246 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1247
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001248class MiscTests(unittest.TestCase):
1249
1250 def test_build_opener(self):
1251 class MyHTTPHandler(urllib2.HTTPHandler): pass
1252 class FooHandler(urllib2.BaseHandler):
1253 def foo_open(self): pass
1254 class BarHandler(urllib2.BaseHandler):
1255 def bar_open(self): pass
1256
1257 build_opener = urllib2.build_opener
1258
1259 o = build_opener(FooHandler, BarHandler)
1260 self.opener_has_handler(o, FooHandler)
1261 self.opener_has_handler(o, BarHandler)
1262
1263 # can take a mix of classes and instances
1264 o = build_opener(FooHandler, BarHandler())
1265 self.opener_has_handler(o, FooHandler)
1266 self.opener_has_handler(o, BarHandler)
1267
1268 # subclasses of default handlers override default handlers
1269 o = build_opener(MyHTTPHandler)
1270 self.opener_has_handler(o, MyHTTPHandler)
1271
1272 # a particular case of overriding: default handlers can be passed
1273 # in explicitly
1274 o = build_opener()
1275 self.opener_has_handler(o, urllib2.HTTPHandler)
1276 o = build_opener(urllib2.HTTPHandler)
1277 self.opener_has_handler(o, urllib2.HTTPHandler)
1278 o = build_opener(urllib2.HTTPHandler())
1279 self.opener_has_handler(o, urllib2.HTTPHandler)
1280
Amaury Forgeot d'Arc96865852008-04-22 21:14:41 +00001281 # Issue2670: multiple handlers sharing the same base class
1282 class MyOtherHTTPHandler(urllib2.HTTPHandler): pass
1283 o = build_opener(MyHTTPHandler, MyOtherHTTPHandler)
1284 self.opener_has_handler(o, MyHTTPHandler)
1285 self.opener_has_handler(o, MyOtherHTTPHandler)
1286
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001287 def opener_has_handler(self, opener, handler_class):
1288 for h in opener.handlers:
1289 if h.__class__ == handler_class:
1290 break
1291 else:
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001292 self.assertTrue(False)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001293
Berker Peksag87640b32016-03-06 16:27:23 +02001294 def test_unsupported_algorithm(self):
1295 handler = AbstractDigestAuthHandler()
1296 with self.assertRaises(ValueError) as exc:
1297 handler.get_algorithm_impls('invalid')
1298 self.assertEqual(
1299 str(exc.exception),
1300 "Unsupported digest authentication algorithm 'invalid'"
1301 )
1302
1303
Jeremy Hylton1868d7c2008-12-09 21:03:10 +00001304class RequestTests(unittest.TestCase):
1305
1306 def setUp(self):
1307 self.get = urllib2.Request("http://www.python.org/~jeremy/")
1308 self.post = urllib2.Request("http://www.python.org/~jeremy/",
1309 "data",
1310 headers={"X-Test": "test"})
1311
1312 def test_method(self):
1313 self.assertEqual("POST", self.post.get_method())
1314 self.assertEqual("GET", self.get.get_method())
1315
1316 def test_add_data(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001317 self.assertTrue(not self.get.has_data())
Jeremy Hylton1868d7c2008-12-09 21:03:10 +00001318 self.assertEqual("GET", self.get.get_method())
1319 self.get.add_data("spam")
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001320 self.assertTrue(self.get.has_data())
Jeremy Hylton1868d7c2008-12-09 21:03:10 +00001321 self.assertEqual("POST", self.get.get_method())
1322
1323 def test_get_full_url(self):
1324 self.assertEqual("http://www.python.org/~jeremy/",
1325 self.get.get_full_url())
1326
1327 def test_selector(self):
1328 self.assertEqual("/~jeremy/", self.get.get_selector())
1329 req = urllib2.Request("http://www.python.org/")
1330 self.assertEqual("/", req.get_selector())
1331
1332 def test_get_type(self):
1333 self.assertEqual("http", self.get.get_type())
1334
1335 def test_get_host(self):
1336 self.assertEqual("www.python.org", self.get.get_host())
1337
1338 def test_get_host_unquote(self):
1339 req = urllib2.Request("http://www.%70ython.org/")
1340 self.assertEqual("www.python.org", req.get_host())
1341
1342 def test_proxy(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001343 self.assertTrue(not self.get.has_proxy())
Jeremy Hylton1868d7c2008-12-09 21:03:10 +00001344 self.get.set_proxy("www.perl.org", "http")
Benjamin Peterson5c8da862009-06-30 22:57:08 +00001345 self.assertTrue(self.get.has_proxy())
Jeremy Hylton1868d7c2008-12-09 21:03:10 +00001346 self.assertEqual("www.python.org", self.get.get_origin_req_host())
1347 self.assertEqual("www.perl.org", self.get.get_host())
1348
Senthil Kumaranb4ec7ee2010-08-08 11:43:45 +00001349 def test_wrapped_url(self):
1350 req = Request("<URL:http://www.python.org>")
1351 self.assertEqual("www.python.org", req.get_host())
1352
Senthil Kumaran49c44082011-04-13 07:31:45 +08001353 def test_url_fragment(self):
Senthil Kumaranb4ec7ee2010-08-08 11:43:45 +00001354 req = Request("http://www.python.org/?qs=query#fragment=true")
1355 self.assertEqual("/?qs=query", req.get_selector())
1356 req = Request("http://www.python.org/#fun=true")
1357 self.assertEqual("/", req.get_selector())
1358
Senthil Kumaran49c44082011-04-13 07:31:45 +08001359 # Issue 11703: geturl() omits fragment in the original URL.
1360 url = 'http://docs.python.org/library/urllib2.html#OK'
1361 req = Request(url)
1362 self.assertEqual(req.get_full_url(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001363
Serhiy Storchaka43beaeb2016-01-18 10:35:40 +02001364 def test_private_attributes(self):
1365 self.assertFalse(hasattr(self.get, '_Request__r_xxx'))
1366 # Issue #6500: infinite recursion
1367 self.assertFalse(hasattr(self.get, '_Request__r_method'))
1368
Senthil Kumaranf8a6b002012-12-23 09:00:47 -08001369 def test_HTTPError_interface(self):
1370 """
1371 Issue 13211 reveals that HTTPError didn't implement the URLError
1372 interface even though HTTPError is a subclass of URLError.
Jason R. Coombs974d8632011-11-07 10:44:25 -05001373
Senthil Kumaranf8a6b002012-12-23 09:00:47 -08001374 >>> err = urllib2.HTTPError(msg='something bad happened', url=None, code=None, hdrs=None, fp=None)
1375 >>> assert hasattr(err, 'reason')
1376 >>> err.reason
1377 'something bad happened'
1378 """
1379
1380 def test_HTTPError_interface_call(self):
1381 """
1382 Issue 15701= - HTTPError interface has info method available from URLError.
1383 """
1384 err = urllib2.HTTPError(msg='something bad happened', url=None,
1385 code=None, hdrs='Content-Length:42', fp=None)
1386 self.assertTrue(hasattr(err, 'reason'))
1387 assert hasattr(err, 'reason')
1388 assert hasattr(err, 'info')
1389 assert callable(err.info)
1390 try:
1391 err.info()
1392 except AttributeError:
1393 self.fail("err.info() failed")
1394 self.assertEqual(err.info(), "Content-Length:42")
Jason R. Coombs974d8632011-11-07 10:44:25 -05001395
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001396def test_main(verbose=None):
Georg Brandlfa42bd72006-04-30 07:06:11 +00001397 from test import test_urllib2
1398 test_support.run_doctest(test_urllib2, verbose)
Georg Brandl720096a2006-04-02 20:45:34 +00001399 test_support.run_doctest(urllib2, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001400 tests = (TrivialTests,
1401 OpenerDirectorTests,
1402 HandlerTests,
Jeremy Hylton1868d7c2008-12-09 21:03:10 +00001403 MiscTests,
1404 RequestTests)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001405 test_support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001406
1407if __name__ == "__main__":
1408 test_main(verbose=True)