blob: c9dcf5ef7be47d64a89563a41631aa7951ac5203 [file] [log] [blame]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001import unittest
2from test import test_support
3
Andrew M. Kuchling85064ff2004-07-10 19:46:40 +00004import os, socket
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00005import StringIO
Jeremy Hyltone3e61042001-05-09 15:50:25 +00006
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00007import urllib2
8from urllib2 import Request, OpenerDirector
Jeremy Hyltone3e61042001-05-09 15:50:25 +00009
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000010# XXX
11# Request
12# CacheFTPHandler (hard to write)
Georg Brandlfa42bd72006-04-30 07:06:11 +000013# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
Jeremy Hyltone3e61042001-05-09 15:50:25 +000014
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000015class TrivialTests(unittest.TestCase):
16 def test_trivial(self):
17 # A couple trivial tests
Guido van Rossume2ae77b2001-10-24 20:42:55 +000018
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000019 self.assertRaises(ValueError, urllib2.urlopen, 'bogus url')
Tim Peters861adac2001-07-16 20:49:49 +000020
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000021 # XXX Name hacking to get this to work on Windows.
22 fname = os.path.abspath(urllib2.__file__).replace('\\', '/')
23 if fname[1:2] == ":":
24 fname = fname[2:]
25 # And more hacking to get it to work on MacOS. This assumes
26 # urllib.pathname2url works, unfortunately...
27 if os.name == 'mac':
28 fname = '/' + fname.replace(':', '/')
29 elif os.name == 'riscos':
30 import string
31 fname = os.expand(fname)
32 fname = fname.translate(string.maketrans("/.", "./"))
33
34 file_url = "file://%s" % fname
35 f = urllib2.urlopen(file_url)
36
37 buf = f.read()
38 f.close()
Tim Petersf5f32b42005-07-17 23:16:17 +000039
Georg Brandle1b13d22005-08-24 22:20:32 +000040 def test_parse_http_list(self):
41 tests = [('a,b,c', ['a', 'b', 'c']),
42 ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']),
43 ('a, b, "c", "d", "e,f", g, h', ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']),
44 ('a="b\\"c", d="e\\,f", g="h\\\\i"', ['a="b"c"', 'd="e,f"', 'g="h\\i"'])]
45 for string, list in tests:
46 self.assertEquals(urllib2.parse_http_list(string), list)
47
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +000048
Georg Brandl8c036cc2006-08-20 13:15:39 +000049def test_request_headers_dict():
50 """
51 The Request.headers dictionary is not a documented interface. It should
52 stay that way, because the complete set of headers are only accessible
53 through the .get_header(), .has_header(), .header_items() interface.
54 However, .headers pre-dates those methods, and so real code will be using
55 the dictionary.
56
57 The introduction in 2.4 of those methods was a mistake for the same reason:
58 code that previously saw all (urllib2 user)-provided headers in .headers
59 now sees only a subset (and the function interface is ugly and incomplete).
60 A better change would have been to replace .headers dict with a dict
61 subclass (or UserDict.DictMixin instance?) that preserved the .headers
62 interface and also provided access to the "unredirected" headers. It's
63 probably too late to fix that, though.
64
65
66 Check .capitalize() case normalization:
67
68 >>> url = "http://example.com"
69 >>> Request(url, headers={"Spam-eggs": "blah"}).headers["Spam-eggs"]
70 'blah'
71 >>> Request(url, headers={"spam-EggS": "blah"}).headers["Spam-eggs"]
72 'blah'
73
74 Currently, Request(url, "Spam-eggs").headers["Spam-Eggs"] raises KeyError,
75 but that could be changed in future.
76
77 """
78
79def test_request_headers_methods():
80 """
81 Note the case normalization of header names here, to .capitalize()-case.
82 This should be preserved for backwards-compatibility. (In the HTTP case,
83 normalization to .title()-case is done by urllib2 before sending headers to
84 httplib).
85
86 >>> url = "http://example.com"
87 >>> r = Request(url, headers={"Spam-eggs": "blah"})
88 >>> r.has_header("Spam-eggs")
89 True
90 >>> r.header_items()
91 [('Spam-eggs', 'blah')]
92 >>> r.add_header("Foo-Bar", "baz")
93 >>> items = r.header_items()
94 >>> items.sort()
95 >>> items
96 [('Foo-bar', 'baz'), ('Spam-eggs', 'blah')]
97
98 Note that e.g. r.has_header("spam-EggS") is currently False, and
99 r.get_header("spam-EggS") returns None, but that could be changed in
100 future.
101
102 >>> r.has_header("Not-there")
103 False
104 >>> print r.get_header("Not-there")
105 None
106 >>> r.get_header("Not-there", "default")
107 'default'
108
109 """
110
111
Georg Brandlfa42bd72006-04-30 07:06:11 +0000112def test_password_manager(self):
113 """
114 >>> mgr = urllib2.HTTPPasswordMgr()
115 >>> add = mgr.add_password
116 >>> add("Some Realm", "http://example.com/", "joe", "password")
117 >>> add("Some Realm", "http://example.com/ni", "ni", "ni")
118 >>> add("c", "http://example.com/foo", "foo", "ni")
119 >>> add("c", "http://example.com/bar", "bar", "nini")
120 >>> add("b", "http://example.com/", "first", "blah")
121 >>> add("b", "http://example.com/", "second", "spam")
122 >>> add("a", "http://example.com", "1", "a")
123 >>> add("Some Realm", "http://c.example.com:3128", "3", "c")
124 >>> add("Some Realm", "d.example.com", "4", "d")
125 >>> add("Some Realm", "e.example.com:3128", "5", "e")
126
127 >>> mgr.find_user_password("Some Realm", "example.com")
128 ('joe', 'password')
129 >>> mgr.find_user_password("Some Realm", "http://example.com")
130 ('joe', 'password')
131 >>> mgr.find_user_password("Some Realm", "http://example.com/")
132 ('joe', 'password')
133 >>> mgr.find_user_password("Some Realm", "http://example.com/spam")
134 ('joe', 'password')
135 >>> mgr.find_user_password("Some Realm", "http://example.com/spam/spam")
136 ('joe', 'password')
137 >>> mgr.find_user_password("c", "http://example.com/foo")
138 ('foo', 'ni')
139 >>> mgr.find_user_password("c", "http://example.com/bar")
140 ('bar', 'nini')
141
Georg Brandl2b330372006-05-28 20:23:12 +0000142 Actually, this is really undefined ATM
143## Currently, we use the highest-level path where more than one match:
Georg Brandlfa42bd72006-04-30 07:06:11 +0000144
Georg Brandl2b330372006-05-28 20:23:12 +0000145## >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
146## ('joe', 'password')
Georg Brandlfa42bd72006-04-30 07:06:11 +0000147
148 Use latest add_password() in case of conflict:
149
150 >>> mgr.find_user_password("b", "http://example.com/")
151 ('second', 'spam')
152
153 No special relationship between a.example.com and example.com:
154
155 >>> mgr.find_user_password("a", "http://example.com/")
156 ('1', 'a')
157 >>> mgr.find_user_password("a", "http://a.example.com/")
158 (None, None)
159
160 Ports:
161
162 >>> mgr.find_user_password("Some Realm", "c.example.com")
163 (None, None)
164 >>> mgr.find_user_password("Some Realm", "c.example.com:3128")
165 ('3', 'c')
166 >>> mgr.find_user_password("Some Realm", "http://c.example.com:3128")
167 ('3', 'c')
168 >>> mgr.find_user_password("Some Realm", "d.example.com")
169 ('4', 'd')
170 >>> mgr.find_user_password("Some Realm", "e.example.com:3128")
171 ('5', 'e')
172
173 """
174 pass
175
176
Georg Brandl2b330372006-05-28 20:23:12 +0000177def test_password_manager_default_port(self):
178 """
179 >>> mgr = urllib2.HTTPPasswordMgr()
180 >>> add = mgr.add_password
181
182 The point to note here is that we can't guess the default port if there's
183 no scheme. This applies to both add_password and find_user_password.
184
185 >>> add("f", "http://g.example.com:80", "10", "j")
186 >>> add("g", "http://h.example.com", "11", "k")
187 >>> add("h", "i.example.com:80", "12", "l")
188 >>> add("i", "j.example.com", "13", "m")
189 >>> mgr.find_user_password("f", "g.example.com:100")
190 (None, None)
191 >>> mgr.find_user_password("f", "g.example.com:80")
192 ('10', 'j')
193 >>> mgr.find_user_password("f", "g.example.com")
194 (None, None)
195 >>> mgr.find_user_password("f", "http://g.example.com:100")
196 (None, None)
197 >>> mgr.find_user_password("f", "http://g.example.com:80")
198 ('10', 'j')
199 >>> mgr.find_user_password("f", "http://g.example.com")
200 ('10', 'j')
201 >>> mgr.find_user_password("g", "h.example.com")
202 ('11', 'k')
203 >>> mgr.find_user_password("g", "h.example.com:80")
204 ('11', 'k')
205 >>> mgr.find_user_password("g", "http://h.example.com:80")
206 ('11', 'k')
207 >>> mgr.find_user_password("h", "i.example.com")
208 (None, None)
209 >>> mgr.find_user_password("h", "i.example.com:80")
210 ('12', 'l')
211 >>> mgr.find_user_password("h", "http://i.example.com:80")
212 ('12', 'l')
213 >>> mgr.find_user_password("i", "j.example.com")
214 ('13', 'm')
215 >>> mgr.find_user_password("i", "j.example.com:80")
216 (None, None)
217 >>> mgr.find_user_password("i", "http://j.example.com")
218 ('13', 'm')
219 >>> mgr.find_user_password("i", "http://j.example.com:80")
220 (None, None)
221
222 """
223
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000224class MockOpener:
225 addheaders = []
226 def open(self, req, data=None):
227 self.req, self.data = req, data
228 def error(self, proto, *args):
229 self.proto, self.args = proto, args
230
231class MockFile:
232 def read(self, count=None): pass
233 def readline(self, count=None): pass
234 def close(self): pass
235
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000236class MockHeaders(dict):
237 def getheaders(self, name):
238 return self.values()
239
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000240class MockResponse(StringIO.StringIO):
241 def __init__(self, code, msg, headers, data, url=None):
242 StringIO.StringIO.__init__(self, data)
243 self.code, self.msg, self.headers, self.url = code, msg, headers, url
244 def info(self):
245 return self.headers
246 def geturl(self):
247 return self.url
248
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000249class MockCookieJar:
250 def add_cookie_header(self, request):
251 self.ach_req = request
252 def extract_cookies(self, response, request):
253 self.ec_req, self.ec_r = request, response
254
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000255class FakeMethod:
256 def __init__(self, meth_name, action, handle):
257 self.meth_name = meth_name
258 self.handle = handle
259 self.action = action
260 def __call__(self, *args):
261 return self.handle(self.meth_name, self.action, *args)
262
263class MockHandler:
Georg Brandlfa42bd72006-04-30 07:06:11 +0000264 # useful for testing handler machinery
265 # see add_ordered_mock_handlers() docstring
Georg Brandl720096a2006-04-02 20:45:34 +0000266 handler_order = 500
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000267 def __init__(self, methods):
268 self._define_methods(methods)
269 def _define_methods(self, methods):
270 for spec in methods:
271 if len(spec) == 2: name, action = spec
272 else: name, action = spec, None
273 meth = FakeMethod(name, action, self.handle)
274 setattr(self.__class__, name, meth)
275 def handle(self, fn_name, action, *args, **kwds):
276 self.parent.calls.append((self, fn_name, args, kwds))
277 if action is None:
278 return None
279 elif action == "return self":
280 return self
281 elif action == "return response":
282 res = MockResponse(200, "OK", {}, "")
283 return res
284 elif action == "return request":
285 return Request("http://blah/")
286 elif action.startswith("error"):
287 code = action[action.rfind(" ")+1:]
288 try:
289 code = int(code)
290 except ValueError:
291 pass
292 res = MockResponse(200, "OK", {}, "")
293 return self.parent.error("http", args[0], res, code, "", {})
294 elif action == "raise":
295 raise urllib2.URLError("blah")
296 assert False
297 def close(self): pass
298 def add_parent(self, parent):
299 self.parent = parent
300 self.parent.calls = []
301 def __lt__(self, other):
302 if not hasattr(other, "handler_order"):
303 # No handler_order, leave in original order. Yuck.
304 return True
305 return self.handler_order < other.handler_order
306
307def add_ordered_mock_handlers(opener, meth_spec):
308 """Create MockHandlers and add them to an OpenerDirector.
309
310 meth_spec: list of lists of tuples and strings defining methods to define
311 on handlers. eg:
312
313 [["http_error", "ftp_open"], ["http_open"]]
314
315 defines methods .http_error() and .ftp_open() on one handler, and
316 .http_open() on another. These methods just record their arguments and
317 return None. Using a tuple instead of a string causes the method to
318 perform some action (see MockHandler.handle()), eg:
319
320 [["http_error"], [("http_open", "return request")]]
321
322 defines .http_error() on one handler (which simply returns None), and
323 .http_open() on another handler, which returns a Request object.
324
325 """
326 handlers = []
327 count = 0
328 for meths in meth_spec:
329 class MockHandlerSubclass(MockHandler): pass
330 h = MockHandlerSubclass(meths)
Georg Brandl720096a2006-04-02 20:45:34 +0000331 h.handler_order += count
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000332 h.add_parent(opener)
333 count = count + 1
334 handlers.append(h)
335 opener.add_handler(h)
336 return handlers
337
Georg Brandlfa42bd72006-04-30 07:06:11 +0000338def build_test_opener(*handler_instances):
339 opener = OpenerDirector()
340 for h in handler_instances:
341 opener.add_handler(h)
342 return opener
343
344class MockHTTPHandler(urllib2.BaseHandler):
345 # useful for testing redirections and auth
346 # sends supplied headers and code as first response
347 # sends 200 OK as second response
348 def __init__(self, code, headers):
349 self.code = code
350 self.headers = headers
351 self.reset()
352 def reset(self):
353 self._count = 0
354 self.requests = []
355 def http_open(self, req):
356 import mimetools, httplib, copy
357 from StringIO import StringIO
358 self.requests.append(copy.deepcopy(req))
359 if self._count == 0:
360 self._count = self._count + 1
361 name = httplib.responses[self.code]
362 msg = mimetools.Message(StringIO(self.headers))
363 return self.parent.error(
364 "http", req, MockFile(), self.code, name, msg)
365 else:
366 self.req = req
367 msg = mimetools.Message(StringIO("\r\n\r\n"))
368 return MockResponse(200, "OK", msg, "", req.get_full_url())
369
370class MockPasswordManager:
371 def add_password(self, realm, uri, user, password):
372 self.realm = realm
373 self.url = uri
374 self.user = user
375 self.password = password
376 def find_user_password(self, realm, authuri):
377 self.target_realm = realm
378 self.target_url = authuri
379 return self.user, self.password
380
381
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000382class OpenerDirectorTests(unittest.TestCase):
383
Georg Brandl261e2512006-05-29 20:52:54 +0000384 def test_badly_named_methods(self):
385 # test work-around for three methods that accidentally follow the
386 # naming conventions for handler methods
387 # (*_open() / *_request() / *_response())
388
389 # These used to call the accidentally-named methods, causing a
390 # TypeError in real code; here, returning self from these mock
391 # methods would either cause no exception, or AttributeError.
392
393 from urllib2 import URLError
394
395 o = OpenerDirector()
396 meth_spec = [
397 [("do_open", "return self"), ("proxy_open", "return self")],
398 [("redirect_request", "return self")],
399 ]
400 handlers = add_ordered_mock_handlers(o, meth_spec)
401 o.add_handler(urllib2.UnknownHandler())
402 for scheme in "do", "proxy", "redirect":
403 self.assertRaises(URLError, o.open, scheme+"://example.com/")
404
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000405 def test_handled(self):
406 # handler returning non-None means no more handlers will be called
407 o = OpenerDirector()
408 meth_spec = [
409 ["http_open", "ftp_open", "http_error_302"],
410 ["ftp_open"],
411 [("http_open", "return self")],
412 [("http_open", "return self")],
413 ]
414 handlers = add_ordered_mock_handlers(o, meth_spec)
415
416 req = Request("http://example.com/")
417 r = o.open(req)
418 # Second .http_open() gets called, third doesn't, since second returned
419 # non-None. Handlers without .http_open() never get any methods called
420 # on them.
421 # In fact, second mock handler defining .http_open() returns self
422 # (instead of response), which becomes the OpenerDirector's return
423 # value.
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000424 self.assertEqual(r, handlers[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000425 calls = [(handlers[0], "http_open"), (handlers[2], "http_open")]
426 for expected, got in zip(calls, o.calls):
427 handler, name, args, kwds = got
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000428 self.assertEqual((handler, name), expected)
429 self.assertEqual(args, (req,))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000430
431 def test_handler_order(self):
432 o = OpenerDirector()
433 handlers = []
434 for meths, handler_order in [
435 ([("http_open", "return self")], 500),
436 (["http_open"], 0),
437 ]:
438 class MockHandlerSubclass(MockHandler): pass
439 h = MockHandlerSubclass(meths)
440 h.handler_order = handler_order
441 handlers.append(h)
442 o.add_handler(h)
443
444 r = o.open("http://example.com/")
445 # handlers called in reverse order, thanks to their sort order
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000446 self.assertEqual(o.calls[0][0], handlers[1])
447 self.assertEqual(o.calls[1][0], handlers[0])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000448
449 def test_raise(self):
450 # raising URLError stops processing of request
451 o = OpenerDirector()
452 meth_spec = [
453 [("http_open", "raise")],
454 [("http_open", "return self")],
455 ]
456 handlers = add_ordered_mock_handlers(o, meth_spec)
457
458 req = Request("http://example.com/")
459 self.assertRaises(urllib2.URLError, o.open, req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000460 self.assertEqual(o.calls, [(handlers[0], "http_open", (req,), {})])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000461
462## def test_error(self):
463## # XXX this doesn't actually seem to be used in standard library,
464## # but should really be tested anyway...
465
466 def test_http_error(self):
467 # XXX http_error_default
468 # http errors are a special case
469 o = OpenerDirector()
470 meth_spec = [
471 [("http_open", "error 302")],
472 [("http_error_400", "raise"), "http_open"],
473 [("http_error_302", "return response"), "http_error_303",
474 "http_error"],
475 [("http_error_302")],
476 ]
477 handlers = add_ordered_mock_handlers(o, meth_spec)
478
479 class Unknown:
480 def __eq__(self, other): return True
481
482 req = Request("http://example.com/")
483 r = o.open(req)
484 assert len(o.calls) == 2
485 calls = [(handlers[0], "http_open", (req,)),
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000486 (handlers[2], "http_error_302",
487 (req, Unknown(), 302, "", {}))]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000488 for expected, got in zip(calls, o.calls):
489 handler, method_name, args = expected
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000490 self.assertEqual((handler, method_name), got[:2])
491 self.assertEqual(args, got[2])
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000492
493 def test_processors(self):
494 # *_request / *_response methods get called appropriately
495 o = OpenerDirector()
496 meth_spec = [
497 [("http_request", "return request"),
498 ("http_response", "return response")],
499 [("http_request", "return request"),
500 ("http_response", "return response")],
501 ]
502 handlers = add_ordered_mock_handlers(o, meth_spec)
503
504 req = Request("http://example.com/")
505 r = o.open(req)
506 # processor methods are called on *all* handlers that define them,
507 # not just the first handler that handles the request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000508 calls = [
509 (handlers[0], "http_request"), (handlers[1], "http_request"),
510 (handlers[0], "http_response"), (handlers[1], "http_response")]
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000511
512 for i, (handler, name, args, kwds) in enumerate(o.calls):
513 if i < 2:
514 # *_request
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000515 self.assertEqual((handler, name), calls[i])
516 self.assertEqual(len(args), 1)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000517 self.assert_(isinstance(args[0], Request))
518 else:
519 # *_response
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000520 self.assertEqual((handler, name), calls[i])
521 self.assertEqual(len(args), 2)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000522 self.assert_(isinstance(args[0], Request))
523 # response from opener.open is None, because there's no
524 # handler that defines http_open to handle it
525 self.assert_(args[1] is None or
526 isinstance(args[1], MockResponse))
527
528
Tim Peters58eb11c2004-01-18 20:29:55 +0000529def sanepathname2url(path):
530 import urllib
531 urlpath = urllib.pathname2url(path)
532 if os.name == "nt" and urlpath.startswith("///"):
533 urlpath = urlpath[2:]
534 # XXX don't ask me about the mac...
535 return urlpath
536
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000537class HandlerTests(unittest.TestCase):
538
539 def test_ftp(self):
540 class MockFTPWrapper:
541 def __init__(self, data): self.data = data
542 def retrfile(self, filename, filetype):
543 self.filename, self.filetype = filename, filetype
544 return StringIO.StringIO(self.data), len(self.data)
545
546 class NullFTPHandler(urllib2.FTPHandler):
547 def __init__(self, data): self.data = data
Facundo Batista10951d52007-06-06 17:15:23 +0000548 def connect_ftp(self, user, passwd, host, port, dirs, timeout=None):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000549 self.user, self.passwd = user, passwd
550 self.host, self.port = host, port
551 self.dirs = dirs
552 self.ftpwrapper = MockFTPWrapper(self.data)
553 return self.ftpwrapper
554
555 import ftplib, socket
556 data = "rheum rhaponicum"
557 h = NullFTPHandler(data)
558 o = h.parent = MockOpener()
559
560 for url, host, port, type_, dirs, filename, mimetype in [
561 ("ftp://localhost/foo/bar/baz.html",
562 "localhost", ftplib.FTP_PORT, "I",
563 ["foo", "bar"], "baz.html", "text/html"),
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000564 ("ftp://localhost:80/foo/bar/",
565 "localhost", 80, "D",
566 ["foo", "bar"], "", None),
567 ("ftp://localhost/baz.gif;type=a",
568 "localhost", ftplib.FTP_PORT, "A",
569 [], "baz.gif", None), # XXX really this should guess image/gif
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000570 ]:
Facundo Batista10951d52007-06-06 17:15:23 +0000571 req = Request(url)
572 req.timeout = None
573 r = h.ftp_open(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000574 # ftp authentication not yet implemented by FTPHandler
575 self.assert_(h.user == h.passwd == "")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000576 self.assertEqual(h.host, socket.gethostbyname(host))
577 self.assertEqual(h.port, port)
578 self.assertEqual(h.dirs, dirs)
579 self.assertEqual(h.ftpwrapper.filename, filename)
580 self.assertEqual(h.ftpwrapper.filetype, type_)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000581 headers = r.info()
Kurt B. Kaiser3f7cb5d2004-07-11 17:14:13 +0000582 self.assertEqual(headers.get("Content-type"), mimetype)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000583 self.assertEqual(int(headers["Content-length"]), len(data))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000584
585 def test_file(self):
586 import time, rfc822, socket
587 h = urllib2.FileHandler()
588 o = h.parent = MockOpener()
589
Tim Peters58eb11c2004-01-18 20:29:55 +0000590 TESTFN = test_support.TESTFN
591 urlpath = sanepathname2url(os.path.abspath(TESTFN))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000592 towrite = "hello, world\n"
Georg Brandldd2245f2006-03-31 17:18:06 +0000593 urls = [
Tim Peters58eb11c2004-01-18 20:29:55 +0000594 "file://localhost%s" % urlpath,
595 "file://%s" % urlpath,
596 "file://%s%s" % (socket.gethostbyname('localhost'), urlpath),
Georg Brandldd2245f2006-03-31 17:18:06 +0000597 ]
598 try:
Tim Peters480725d2006-04-03 02:46:44 +0000599 localaddr = socket.gethostbyname(socket.gethostname())
Georg Brandldd2245f2006-03-31 17:18:06 +0000600 except socket.gaierror:
601 localaddr = ''
602 if localaddr:
603 urls.append("file://%s%s" % (localaddr, urlpath))
Tim Peters480725d2006-04-03 02:46:44 +0000604
Georg Brandldd2245f2006-03-31 17:18:06 +0000605 for url in urls:
Tim Peters58eb11c2004-01-18 20:29:55 +0000606 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000607 try:
608 try:
609 f.write(towrite)
610 finally:
611 f.close()
612
613 r = h.file_open(Request(url))
614 try:
615 data = r.read()
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000616 headers = r.info()
617 newurl = r.geturl()
618 finally:
619 r.close()
Tim Peters58eb11c2004-01-18 20:29:55 +0000620 stats = os.stat(TESTFN)
621 modified = rfc822.formatdate(stats.st_mtime)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000622 finally:
623 os.remove(TESTFN)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000624 self.assertEqual(data, towrite)
625 self.assertEqual(headers["Content-type"], "text/plain")
626 self.assertEqual(headers["Content-length"], "13")
Tim Peters58eb11c2004-01-18 20:29:55 +0000627 self.assertEqual(headers["Last-modified"], modified)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000628
629 for url in [
Tim Peters58eb11c2004-01-18 20:29:55 +0000630 "file://localhost:80%s" % urlpath,
Georg Brandlceede5c2007-03-13 08:14:27 +0000631 "file:///file_does_not_exist.txt",
632 "file://%s:80%s/%s" % (socket.gethostbyname('localhost'),
633 os.getcwd(), TESTFN),
634 "file://somerandomhost.ontheinternet.com%s/%s" %
635 (os.getcwd(), TESTFN),
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000636 ]:
637 try:
Tim Peters58eb11c2004-01-18 20:29:55 +0000638 f = open(TESTFN, "wb")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000639 try:
640 f.write(towrite)
641 finally:
642 f.close()
643
644 self.assertRaises(urllib2.URLError,
645 h.file_open, Request(url))
646 finally:
647 os.remove(TESTFN)
648
649 h = urllib2.FileHandler()
650 o = h.parent = MockOpener()
651 # XXXX why does // mean ftp (and /// mean not ftp!), and where
652 # is file: scheme specified? I think this is really a bug, and
653 # what was intended was to distinguish between URLs like:
654 # file:/blah.txt (a file)
655 # file://localhost/blah.txt (a file)
656 # file:///blah.txt (a file)
657 # file://ftp.example.com/blah.txt (an ftp URL)
658 for url, ftp in [
659 ("file://ftp.example.com//foo.txt", True),
660 ("file://ftp.example.com///foo.txt", False),
661# XXXX bug: fails with OSError, should be URLError
662 ("file://ftp.example.com/foo.txt", False),
663 ]:
664 req = Request(url)
665 try:
666 h.file_open(req)
667 # XXXX remove OSError when bug fixed
668 except (urllib2.URLError, OSError):
669 self.assert_(not ftp)
670 else:
671 self.assert_(o.req is req)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000672 self.assertEqual(req.type, "ftp")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000673
674 def test_http(self):
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000675 class MockHTTPResponse:
676 def __init__(self, fp, msg, status, reason):
677 self.fp = fp
678 self.msg = msg
679 self.status = status
680 self.reason = reason
Jeremy Hylton5d9c3032004-08-07 17:40:50 +0000681 def read(self):
682 return ''
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000683 class MockHTTPClass:
684 def __init__(self):
685 self.req_headers = []
686 self.data = None
687 self.raise_on_endheaders = False
Facundo Batista10951d52007-06-06 17:15:23 +0000688 def __call__(self, host, timeout=None):
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000689 self.host = host
Facundo Batista10951d52007-06-06 17:15:23 +0000690 self.timeout = timeout
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000691 return self
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000692 def set_debuglevel(self, level):
693 self.level = level
694 def request(self, method, url, body=None, headers={}):
695 self.method = method
696 self.selector = url
697 self.req_headers += headers.items()
Armin Rigoa3f09272006-05-28 19:13:17 +0000698 self.req_headers.sort()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000699 if body:
700 self.data = body
701 if self.raise_on_endheaders:
702 import socket
703 raise socket.error()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000704 def getresponse(self):
705 return MockHTTPResponse(MockFile(), {}, 200, "OK")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000706
707 h = urllib2.AbstractHTTPHandler()
708 o = h.parent = MockOpener()
709
710 url = "http://example.com/"
711 for method, data in [("GET", None), ("POST", "blah")]:
712 req = Request(url, data, {"Foo": "bar"})
Facundo Batista10951d52007-06-06 17:15:23 +0000713 req.timeout = None
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000714 req.add_unredirected_header("Spam", "eggs")
715 http = MockHTTPClass()
716 r = h.do_open(http, req)
717
718 # result attributes
719 r.read; r.readline # wrapped MockFile methods
720 r.info; r.geturl # addinfourl methods
721 r.code, r.msg == 200, "OK" # added from MockHTTPClass.getreply()
722 hdrs = r.info()
723 hdrs.get; hdrs.has_key # r.info() gives dict from .getreply()
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000724 self.assertEqual(r.geturl(), url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000725
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000726 self.assertEqual(http.host, "example.com")
727 self.assertEqual(http.level, 0)
728 self.assertEqual(http.method, method)
729 self.assertEqual(http.selector, "/")
730 self.assertEqual(http.req_headers,
Jeremy Hyltonb3ee6f92004-02-24 19:40:35 +0000731 [("Connection", "close"),
732 ("Foo", "bar"), ("Spam", "eggs")])
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000733 self.assertEqual(http.data, data)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000734
735 # check socket.error converted to URLError
736 http.raise_on_endheaders = True
737 self.assertRaises(urllib2.URLError, h.do_open, http, req)
738
739 # check adding of standard headers
740 o.addheaders = [("Spam", "eggs")]
741 for data in "", None: # POST, GET
742 req = Request("http://example.com/", data)
743 r = MockResponse(200, "OK", {}, "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000744 newreq = h.do_request_(req)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000745 if data is None: # GET
Georg Brandl8c036cc2006-08-20 13:15:39 +0000746 self.assert_("Content-length" not in req.unredirected_hdrs)
747 self.assert_("Content-type" not in req.unredirected_hdrs)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000748 else: # POST
Georg Brandl8c036cc2006-08-20 13:15:39 +0000749 self.assertEqual(req.unredirected_hdrs["Content-length"], "0")
750 self.assertEqual(req.unredirected_hdrs["Content-type"],
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000751 "application/x-www-form-urlencoded")
752 # XXX the details of Host could be better tested
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000753 self.assertEqual(req.unredirected_hdrs["Host"], "example.com")
754 self.assertEqual(req.unredirected_hdrs["Spam"], "eggs")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000755
756 # don't clobber existing headers
757 req.add_unredirected_header("Content-length", "foo")
758 req.add_unredirected_header("Content-type", "bar")
759 req.add_unredirected_header("Host", "baz")
760 req.add_unredirected_header("Spam", "foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000761 newreq = h.do_request_(req)
Georg Brandl8c036cc2006-08-20 13:15:39 +0000762 self.assertEqual(req.unredirected_hdrs["Content-length"], "foo")
763 self.assertEqual(req.unredirected_hdrs["Content-type"], "bar")
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000764 self.assertEqual(req.unredirected_hdrs["Host"], "baz")
765 self.assertEqual(req.unredirected_hdrs["Spam"], "foo")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000766
767 def test_errors(self):
768 h = urllib2.HTTPErrorProcessor()
769 o = h.parent = MockOpener()
770
771 url = "http://example.com/"
772 req = Request(url)
Facundo Batista9fab9f12007-04-23 17:08:31 +0000773 # all 2xx are passed through
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000774 r = MockResponse(200, "OK", {}, "", url)
775 newr = h.http_response(req, r)
776 self.assert_(r is newr)
777 self.assert_(not hasattr(o, "proto")) # o.error not called
Facundo Batista9fab9f12007-04-23 17:08:31 +0000778 r = MockResponse(202, "Accepted", {}, "", url)
779 newr = h.http_response(req, r)
780 self.assert_(r is newr)
781 self.assert_(not hasattr(o, "proto")) # o.error not called
782 r = MockResponse(206, "Partial content", {}, "", url)
783 newr = h.http_response(req, r)
784 self.assert_(r is newr)
785 self.assert_(not hasattr(o, "proto")) # o.error not called
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000786 # anything else calls o.error (and MockOpener returns None, here)
Facundo Batista9fab9f12007-04-23 17:08:31 +0000787 r = MockResponse(502, "Bad gateway", {}, "", url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000788 self.assert_(h.http_response(req, r) is None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000789 self.assertEqual(o.proto, "http") # o.error called
Facundo Batista9fab9f12007-04-23 17:08:31 +0000790 self.assertEqual(o.args, (req, r, 502, "Bad gateway", {}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000791
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000792 def test_cookies(self):
793 cj = MockCookieJar()
794 h = urllib2.HTTPCookieProcessor(cj)
795 o = h.parent = MockOpener()
796
797 req = Request("http://example.com/")
798 r = MockResponse(200, "OK", {}, "")
799 newreq = h.http_request(req)
800 self.assert_(cj.ach_req is req is newreq)
801 self.assertEquals(req.get_origin_req_host(), "example.com")
802 self.assert_(not req.is_unverifiable())
803 newr = h.http_response(req, r)
804 self.assert_(cj.ec_req is req)
805 self.assert_(cj.ec_r is r is newr)
806
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000807 def test_redirect(self):
808 from_url = "http://example.com/a.html"
809 to_url = "http://example.com/b.html"
810 h = urllib2.HTTPRedirectHandler()
811 o = h.parent = MockOpener()
812
813 # ordinary redirect behaviour
814 for code in 301, 302, 303, 307:
815 for data in None, "blah\nblah\n":
816 method = getattr(h, "http_error_%s" % code)
817 req = Request(from_url, data)
818 req.add_header("Nonsense", "viking=withhold")
819 req.add_unredirected_header("Spam", "spam")
820 try:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000821 method(req, MockFile(), code, "Blah",
822 MockHeaders({"location": to_url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000823 except urllib2.HTTPError:
824 # 307 in response to POST requires user OK
825 self.assert_(code == 307 and data is not None)
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000826 self.assertEqual(o.req.get_full_url(), to_url)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000827 try:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000828 self.assertEqual(o.req.get_method(), "GET")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000829 except AttributeError:
830 self.assert_(not o.req.has_data())
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000831 self.assertEqual(o.req.headers["Nonsense"],
832 "viking=withhold")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000833 self.assert_("Spam" not in o.req.headers)
834 self.assert_("Spam" not in o.req.unredirected_hdrs)
835
836 # loop detection
837 req = Request(from_url)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000838 def redirect(h, req, url=to_url):
839 h.http_error_302(req, MockFile(), 302, "Blah",
840 MockHeaders({"location": url}))
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000841 # Note that the *original* request shares the same record of
842 # redirections with the sub-requests caused by the redirections.
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000843
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000844 # detect infinite loop redirect of a URL to itself
845 req = Request(from_url, origin_req_host="example.com")
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000846 count = 0
847 try:
848 while 1:
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000849 redirect(h, req, "http://example.com/")
850 count = count + 1
851 except urllib2.HTTPError:
852 # don't stop until max_repeats, because cookies may introduce state
853 self.assertEqual(count, urllib2.HTTPRedirectHandler.max_repeats)
854
855 # detect endless non-repeating chain of redirects
856 req = Request(from_url, origin_req_host="example.com")
857 count = 0
858 try:
859 while 1:
860 redirect(h, req, "http://example.com/%d" % count)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000861 count = count + 1
862 except urllib2.HTTPError:
Jeremy Hyltondf38ea92003-12-17 20:42:38 +0000863 self.assertEqual(count,
864 urllib2.HTTPRedirectHandler.max_redirections)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +0000865
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000866 def test_cookie_redirect(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000867 # cookies shouldn't leak into redirected requests
868 from cookielib import CookieJar
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000869
Neal Norwitzb902f4e2006-04-03 04:45:34 +0000870 from test.test_cookielib import interact_netscape
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000871
872 cj = CookieJar()
873 interact_netscape(cj, "http://www.example.com/", "spam=eggs")
Georg Brandlfa42bd72006-04-30 07:06:11 +0000874 hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
875 hdeh = urllib2.HTTPDefaultErrorHandler()
876 hrh = urllib2.HTTPRedirectHandler()
877 cp = urllib2.HTTPCookieProcessor(cj)
878 o = build_test_opener(hh, hdeh, hrh, cp)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000879 o.open("http://www.example.com/")
880 self.assert_(not hh.req.has_header("Cookie"))
881
Georg Brandl720096a2006-04-02 20:45:34 +0000882 def test_proxy(self):
883 o = OpenerDirector()
884 ph = urllib2.ProxyHandler(dict(http="proxy.example.com:3128"))
885 o.add_handler(ph)
886 meth_spec = [
887 [("http_open", "return response")]
888 ]
889 handlers = add_ordered_mock_handlers(o, meth_spec)
890
891 req = Request("http://acme.example.com/")
892 self.assertEqual(req.get_host(), "acme.example.com")
893 r = o.open(req)
894 self.assertEqual(req.get_host(), "proxy.example.com:3128")
895
896 self.assertEqual([(handlers[0], "http_open")],
897 [tup[0:2] for tup in o.calls])
898
Georg Brandlfa42bd72006-04-30 07:06:11 +0000899 def test_basic_auth(self):
900 opener = OpenerDirector()
901 password_manager = MockPasswordManager()
902 auth_handler = urllib2.HTTPBasicAuthHandler(password_manager)
903 realm = "ACME Widget Store"
904 http_handler = MockHTTPHandler(
905 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Georg Brandl261e2512006-05-29 20:52:54 +0000906 opener.add_handler(auth_handler)
907 opener.add_handler(http_handler)
Georg Brandlfa42bd72006-04-30 07:06:11 +0000908 self._test_basic_auth(opener, auth_handler, "Authorization",
909 realm, http_handler, password_manager,
910 "http://acme.example.com/protected",
911 "http://acme.example.com/protected",
912 )
913
914 def test_proxy_basic_auth(self):
915 opener = OpenerDirector()
916 ph = urllib2.ProxyHandler(dict(http="proxy.example.com:3128"))
917 opener.add_handler(ph)
918 password_manager = MockPasswordManager()
919 auth_handler = urllib2.ProxyBasicAuthHandler(password_manager)
920 realm = "ACME Networks"
921 http_handler = MockHTTPHandler(
922 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Georg Brandl261e2512006-05-29 20:52:54 +0000923 opener.add_handler(auth_handler)
924 opener.add_handler(http_handler)
Georg Brandl8c036cc2006-08-20 13:15:39 +0000925 self._test_basic_auth(opener, auth_handler, "Proxy-authorization",
Georg Brandlfa42bd72006-04-30 07:06:11 +0000926 realm, http_handler, password_manager,
927 "http://acme.example.com:3128/protected",
928 "proxy.example.com:3128",
929 )
930
Georg Brandlb5f2e5c2006-05-08 17:36:08 +0000931 def test_basic_and_digest_auth_handlers(self):
932 # HTTPDigestAuthHandler threw an exception if it couldn't handle a 40*
933 # response (http://python.org/sf/1479302), where it should instead
934 # return None to allow another handler (especially
935 # HTTPBasicAuthHandler) to handle the response.
Georg Brandl261e2512006-05-29 20:52:54 +0000936
937 # Also (http://python.org/sf/14797027, RFC 2617 section 1.2), we must
938 # try digest first (since it's the strongest auth scheme), so we record
939 # order of calls here to check digest comes first:
940 class RecordingOpenerDirector(OpenerDirector):
941 def __init__(self):
942 OpenerDirector.__init__(self)
943 self.recorded = []
944 def record(self, info):
945 self.recorded.append(info)
Georg Brandlb5f2e5c2006-05-08 17:36:08 +0000946 class TestDigestAuthHandler(urllib2.HTTPDigestAuthHandler):
Georg Brandl261e2512006-05-29 20:52:54 +0000947 def http_error_401(self, *args, **kwds):
948 self.parent.record("digest")
949 urllib2.HTTPDigestAuthHandler.http_error_401(self,
950 *args, **kwds)
951 class TestBasicAuthHandler(urllib2.HTTPBasicAuthHandler):
952 def http_error_401(self, *args, **kwds):
953 self.parent.record("basic")
954 urllib2.HTTPBasicAuthHandler.http_error_401(self,
955 *args, **kwds)
956
957 opener = RecordingOpenerDirector()
Georg Brandlb5f2e5c2006-05-08 17:36:08 +0000958 password_manager = MockPasswordManager()
959 digest_handler = TestDigestAuthHandler(password_manager)
Georg Brandl261e2512006-05-29 20:52:54 +0000960 basic_handler = TestBasicAuthHandler(password_manager)
Georg Brandlb5f2e5c2006-05-08 17:36:08 +0000961 realm = "ACME Networks"
962 http_handler = MockHTTPHandler(
963 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
Georg Brandl261e2512006-05-29 20:52:54 +0000964 opener.add_handler(basic_handler)
965 opener.add_handler(digest_handler)
966 opener.add_handler(http_handler)
967
968 # check basic auth isn't blocked by digest handler failing
Georg Brandlb5f2e5c2006-05-08 17:36:08 +0000969 self._test_basic_auth(opener, basic_handler, "Authorization",
970 realm, http_handler, password_manager,
971 "http://acme.example.com/protected",
972 "http://acme.example.com/protected",
973 )
Georg Brandl261e2512006-05-29 20:52:54 +0000974 # check digest was tried before basic (twice, because
975 # _test_basic_auth called .open() twice)
976 self.assertEqual(opener.recorded, ["digest", "basic"]*2)
Georg Brandlb5f2e5c2006-05-08 17:36:08 +0000977
Georg Brandlfa42bd72006-04-30 07:06:11 +0000978 def _test_basic_auth(self, opener, auth_handler, auth_header,
979 realm, http_handler, password_manager,
980 request_url, protected_url):
981 import base64, httplib
982 user, password = "wile", "coyote"
Georg Brandlfa42bd72006-04-30 07:06:11 +0000983
984 # .add_password() fed through to password manager
985 auth_handler.add_password(realm, request_url, user, password)
986 self.assertEqual(realm, password_manager.realm)
987 self.assertEqual(request_url, password_manager.url)
988 self.assertEqual(user, password_manager.user)
989 self.assertEqual(password, password_manager.password)
990
991 r = opener.open(request_url)
992
993 # should have asked the password manager for the username/password
994 self.assertEqual(password_manager.target_realm, realm)
995 self.assertEqual(password_manager.target_url, protected_url)
996
997 # expect one request without authorization, then one with
998 self.assertEqual(len(http_handler.requests), 2)
999 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1000 userpass = '%s:%s' % (user, password)
1001 auth_hdr_value = 'Basic '+base64.encodestring(userpass).strip()
1002 self.assertEqual(http_handler.requests[1].get_header(auth_header),
1003 auth_hdr_value)
1004
1005 # if the password manager can't find a password, the handler won't
1006 # handle the HTTP auth error
1007 password_manager.user = password_manager.password = None
1008 http_handler.reset()
1009 r = opener.open(request_url)
1010 self.assertEqual(len(http_handler.requests), 1)
1011 self.assertFalse(http_handler.requests[0].has_header(auth_header))
1012
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001013
1014class MiscTests(unittest.TestCase):
1015
1016 def test_build_opener(self):
1017 class MyHTTPHandler(urllib2.HTTPHandler): pass
1018 class FooHandler(urllib2.BaseHandler):
1019 def foo_open(self): pass
1020 class BarHandler(urllib2.BaseHandler):
1021 def bar_open(self): pass
1022
1023 build_opener = urllib2.build_opener
1024
1025 o = build_opener(FooHandler, BarHandler)
1026 self.opener_has_handler(o, FooHandler)
1027 self.opener_has_handler(o, BarHandler)
1028
1029 # can take a mix of classes and instances
1030 o = build_opener(FooHandler, BarHandler())
1031 self.opener_has_handler(o, FooHandler)
1032 self.opener_has_handler(o, BarHandler)
1033
1034 # subclasses of default handlers override default handlers
1035 o = build_opener(MyHTTPHandler)
1036 self.opener_has_handler(o, MyHTTPHandler)
1037
1038 # a particular case of overriding: default handlers can be passed
1039 # in explicitly
1040 o = build_opener()
1041 self.opener_has_handler(o, urllib2.HTTPHandler)
1042 o = build_opener(urllib2.HTTPHandler)
1043 self.opener_has_handler(o, urllib2.HTTPHandler)
1044 o = build_opener(urllib2.HTTPHandler())
1045 self.opener_has_handler(o, urllib2.HTTPHandler)
1046
1047 def opener_has_handler(self, opener, handler_class):
1048 for h in opener.handlers:
1049 if h.__class__ == handler_class:
1050 break
1051 else:
1052 self.assert_(False)
1053
1054
1055def test_main(verbose=None):
Georg Brandlfa42bd72006-04-30 07:06:11 +00001056 from test import test_urllib2
1057 test_support.run_doctest(test_urllib2, verbose)
Georg Brandl720096a2006-04-02 20:45:34 +00001058 test_support.run_doctest(urllib2, verbose)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001059 tests = (TrivialTests,
1060 OpenerDirectorTests,
1061 HandlerTests,
1062 MiscTests)
Andrew M. Kuchlingbd3200f2004-06-29 13:15:46 +00001063 test_support.run_unittest(*tests)
Jeremy Hyltonc1be59f2003-12-14 05:27:34 +00001064
1065if __name__ == "__main__":
1066 test_main(verbose=True)