0001 # -*- coding: utf-8 -*- 0002 """Tests for cookielib.py.""" 0003 0004 import re, os, time 0005 from unittest import TestCase 0006 0007 from test import test_support 0008 0009 class DateTimeTests(TestCase): 0010 0011 def test_time2isoz(self): 0012 from cookielib import time2isoz 0013 0014 base = 1019227000 0015 day = 24*3600 0016 self.assertEquals(time2isoz(base), "2002-04-19 14:36:40Z") 0017 self.assertEquals(time2isoz(base+day), "2002-04-20 14:36:40Z") 0018 self.assertEquals(time2isoz(base+2*day), "2002-04-21 14:36:40Z") 0019 self.assertEquals(time2isoz(base+3*day), "2002-04-22 14:36:40Z") 0020 0021 az = time2isoz() 0022 bz = time2isoz(500000) 0023 for text in (az, bz): 0024 self.assert_(re.search(r"^\d{4}-\d\d-\d\d \d\d:\d\d:\d\dZ$", text), 0025 "bad time2isoz format: %s %s" % (az, bz)) 0026 0027 def test_http2time(self): 0028 from cookielib import http2time 0029 0030 def parse_date(text): 0031 return time.gmtime(http2time(text))[:6] 0032 0033 self.assertEquals(parse_date("01 Jan 2001"), (2001, 1, 1, 0, 0, 0.0)) 0034 0035 # this test will break around year 2070 0036 self.assertEquals(parse_date("03-Feb-20"), (2020, 2, 3, 0, 0, 0.0)) 0037 0038 # this test will break around year 2048 0039 self.assertEquals(parse_date("03-Feb-98"), (1998, 2, 3, 0, 0, 0.0)) 0040 0041 def test_http2time_formats(self): 0042 from cookielib import http2time, time2isoz 0043 0044 # test http2time for supported dates. Test cases with 2 digit year 0045 # will probably break in year 2044. 0046 tests = [ 0047 'Thu, 03 Feb 1994 00:00:00 GMT', # proposed new HTTP format 0048 'Thursday, 03-Feb-94 00:00:00 GMT', # old rfc850 HTTP format 0049 'Thursday, 03-Feb-1994 00:00:00 GMT', # broken rfc850 HTTP format 0050 0051 '03 Feb 1994 00:00:00 GMT', # HTTP format (no weekday) 0052 '03-Feb-94 00:00:00 GMT', # old rfc850 (no weekday) 0053 '03-Feb-1994 00:00:00 GMT', # broken rfc850 (no weekday) 0054 '03-Feb-1994 00:00 GMT', # broken rfc850 (no weekday, no seconds) 0055 '03-Feb-1994 00:00', # broken rfc850 (no weekday, no seconds, no tz) 0056 0057 '03-Feb-94', # old rfc850 HTTP format (no weekday, no time) 0058 '03-Feb-1994', # broken rfc850 HTTP format (no weekday, no time) 0059 '03 Feb 1994', # proposed new HTTP format (no weekday, no time) 0060 0061 # A few tests with extra space at various places 0062 ' 03 Feb 1994 0:00 ', 0063 ' 03-Feb-1994 ', 0064 ] 0065 0066 test_t = 760233600 # assume broken POSIX counting of seconds 0067 result = time2isoz(test_t) 0068 expected = "1994-02-03 00:00:00Z" 0069 self.assertEquals(result, expected, 0070 "%s => '%s' (%s)" % (test_t, result, expected)) 0071 0072 for s in tests: 0073 t = http2time(s) 0074 t2 = http2time(s.lower()) 0075 t3 = http2time(s.upper()) 0076 0077 self.assert_(t == t2 == t3 == test_t, 0078 "'%s' => %s, %s, %s (%s)" % (s, t, t2, t3, test_t)) 0079 0080 def test_http2time_garbage(self): 0081 from cookielib import http2time 0082 0083 for test in [ 0084 '', 0085 'Garbage', 0086 'Mandag 16. September 1996', 0087 '01-00-1980', 0088 '01-13-1980', 0089 '00-01-1980', 0090 '32-01-1980', 0091 '01-01-1980 25:00:00', 0092 '01-01-1980 00:61:00', 0093 '01-01-1980 00:00:62', 0094 ]: 0095 self.assert_(http2time(test) is None, 0096 "http2time(%s) is not None\n" 0097 "http2time(test) %s" % (test, http2time(test)) 0098 ) 0099 0100 0101 class HeaderTests(TestCase): 0102 def test_parse_ns_headers(self): 0103 from cookielib import parse_ns_headers 0104 0105 # quotes should be stripped 0106 expected = [[('expires', 2209069412L), ('version', '0')]] 0107 for hdr in [ 0108 'expires=01 Jan 2040 22:23:32 GMT', 0109 'expires="01 Jan 2040 22:23:32 GMT"', 0110 ]: 0111 self.assertEquals(parse_ns_headers([hdr]), expected) 0112 0113 def test_join_header_words(self): 0114 from cookielib import join_header_words 0115 0116 joined = join_header_words([[("foo", None), ("bar", "baz")]]) 0117 self.assertEquals(joined, "foo; bar=baz") 0118 0119 self.assertEquals(join_header_words([[]]), "") 0120 0121 def test_split_header_words(self): 0122 from cookielib import split_header_words 0123 0124 tests = [ 0125 ("foo", [[("foo", None)]]), 0126 ("foo=bar", [[("foo", "bar")]]), 0127 (" foo ", [[("foo", None)]]), 0128 (" foo= ", [[("foo", "")]]), 0129 (" foo=", [[("foo", "")]]), 0130 (" foo= ; ", [[("foo", "")]]), 0131 (" foo= ; bar= baz ", [[("foo", ""), ("bar", "baz")]]), 0132 ("foo=bar bar=baz", [[("foo", "bar"), ("bar", "baz")]]), 0133 # doesn't really matter if this next fails, but it works ATM 0134 ("foo= bar=baz", [[("foo", "bar=baz")]]), 0135 ("foo=bar;bar=baz", [[("foo", "bar"), ("bar", "baz")]]), 0136 ('foo bar baz', [[("foo", None), ("bar", None), ("baz", None)]]), 0137 ("a, b, c", [[("a", None)], [("b", None)], [("c", None)]]), 0138 (r'foo; bar=baz, spam=, foo="\,\;\"", bar= ', 0139 [[("foo", None), ("bar", "baz")], 0140 [("spam", "")], [("foo", ',;"')], [("bar", "")]]), 0141 ] 0142 0143 for arg, expect in tests: 0144 try: 0145 result = split_header_words([arg]) 0146 except: 0147 import traceback, StringIO 0148 f = StringIO.StringIO() 0149 traceback.print_exc(None, f) 0150 result = "(error -- traceback follows)\n\n%s" % f.getvalue() 0151 self.assertEquals(result, expect, """ 0152 When parsing: '%s' 0153 Expected: '%s' 0154 Got: '%s' 0155 """ % (arg, expect, result)) 0156 0157 def test_roundtrip(self): 0158 from cookielib import split_header_words, join_header_words 0159 0160 tests = [ 0161 ("foo", "foo"), 0162 ("foo=bar", "foo=bar"), 0163 (" foo ", "foo"), 0164 ("foo=", 'foo=""'), 0165 ("foo=bar bar=baz", "foo=bar; bar=baz"), 0166 ("foo=bar;bar=baz", "foo=bar; bar=baz"), 0167 ('foo bar baz', "foo; bar; baz"), 0168 (r'foo="\"" bar="\\"', r'foo="\""; bar="\\"'), 0169 ('foo,,,bar', 'foo, bar'), 0170 ('foo=bar,bar=baz', 'foo=bar, bar=baz'), 0171 0172 ('text/html; charset=iso-8859-1', 0173 'text/html; charset="iso-8859-1"'), 0174 0175 ('foo="bar"; port="80,81"; discard, bar=baz', 0176 'foo=bar; port="80,81"; discard, bar=baz'), 0177 0178 (r'Basic realm="\"foo\\\\bar\""', 0179 r'Basic; realm="\"foo\\\\bar\""') 0180 ] 0181 0182 for arg, expect in tests: 0183 input = split_header_words([arg]) 0184 res = join_header_words(input) 0185 self.assertEquals(res, expect, """ 0186 When parsing: '%s' 0187 Expected: '%s' 0188 Got: '%s' 0189 Input was: '%s' 0190 """ % (arg, expect, res, input)) 0191 0192 0193 class FakeResponse: 0194 def __init__(self, headers=[], url=None): 0195 """ 0196 headers: list of RFC822-style 'Key: value' strings 0197 """ 0198 import mimetools, StringIO 0199 f = StringIO.StringIO("\n".join(headers)) 0200 self._headers = mimetools.Message(f) 0201 self._url = url 0202 def info(self): return self._headers 0203 0204 def interact_2965(cookiejar, url, *set_cookie_hdrs): 0205 return _interact(cookiejar, url, set_cookie_hdrs, "Set-Cookie2") 0206 0207 def interact_netscape(cookiejar, url, *set_cookie_hdrs): 0208 return _interact(cookiejar, url, set_cookie_hdrs, "Set-Cookie") 0209 0210 def _interact(cookiejar, url, set_cookie_hdrs, hdr_name): 0211 """Perform a single request / response cycle, returning Cookie: header.""" 0212 from urllib2 import Request 0213 req = Request(url) 0214 cookiejar.add_cookie_header(req) 0215 cookie_hdr = req.get_header("Cookie", "") 0216 headers = [] 0217 for hdr in set_cookie_hdrs: 0218 headers.append("%s: %s" % (hdr_name, hdr)) 0219 res = FakeResponse(headers, url) 0220 cookiejar.extract_cookies(res, req) 0221 return cookie_hdr 0222 0223 0224 class CookieTests(TestCase): 0225 # XXX 0226 # Get rid of string comparisons where not actually testing str / repr. 0227 # .clear() etc. 0228 # IP addresses like 50 (single number, no dot) and domain-matching 0229 # functions (and is_HDN)? See draft RFC 2965 errata. 0230 # Strictness switches 0231 # is_third_party() 0232 # unverifiability / third-party blocking 0233 # Netscape cookies work the same as RFC 2965 with regard to port. 0234 # Set-Cookie with negative max age. 0235 # If turn RFC 2965 handling off, Set-Cookie2 cookies should not clobber 0236 # Set-Cookie cookies. 0237 # Cookie2 should be sent if *any* cookies are not V1 (ie. V0 OR V2 etc.). 0238 # Cookies (V1 and V0) with no expiry date should be set to be discarded. 0239 # RFC 2965 Quoting: 0240 # Should accept unquoted cookie-attribute values? check errata draft. 0241 # Which are required on the way in and out? 0242 # Should always return quoted cookie-attribute values? 0243 # Proper testing of when RFC 2965 clobbers Netscape (waiting for errata). 0244 # Path-match on return (same for V0 and V1). 0245 # RFC 2965 acceptance and returning rules 0246 # Set-Cookie2 without version attribute is rejected. 0247 0248 # Netscape peculiarities list from Ronald Tschalar. 0249 # The first two still need tests, the rest are covered. 0250 ## - Quoting: only quotes around the expires value are recognized as such 0251 ## (and yes, some folks quote the expires value); quotes around any other 0252 ## value are treated as part of the value. 0253 ## - White space: white space around names and values is ignored 0254 ## - Default path: if no path parameter is given, the path defaults to the 0255 ## path in the request-uri up to, but not including, the last '/'. Note 0256 ## that this is entirely different from what the spec says. 0257 ## - Commas and other delimiters: Netscape just parses until the next ';'. 0258 ## This means it will allow commas etc inside values (and yes, both 0259 ## commas and equals are commonly appear in the cookie value). This also 0260 ## means that if you fold multiple Set-Cookie header fields into one, 0261 ## comma-separated list, it'll be a headache to parse (at least my head 0262 ## starts hurting everytime I think of that code). 0263 ## - Expires: You'll get all sorts of date formats in the expires, 0264 ## including emtpy expires attributes ("expires="). Be as flexible as you 0265 ## can, and certainly don't expect the weekday to be there; if you can't 0266 ## parse it, just ignore it and pretend it's a session cookie. 0267 ## - Domain-matching: Netscape uses the 2-dot rule for _all_ domains, not 0268 ## just the 7 special TLD's listed in their spec. And folks rely on 0269 ## that... 0270 0271 def test_domain_return_ok(self): 0272 # test optimization: .domain_return_ok() should filter out most 0273 # domains in the CookieJar before we try to access them (because that 0274 # may require disk access -- in particular, with MSIECookieJar) 0275 # This is only a rough check for performance reasons, so it's not too 0276 # critical as long as it's sufficiently liberal. 0277 import cookielib, urllib2 0278 pol = cookielib.DefaultCookiePolicy() 0279 for url, domain, ok in [ 0280 ("http://foo.bar.com/", "blah.com", False), 0281 ("http://foo.bar.com/", "rhubarb.blah.com", False), 0282 ("http://foo.bar.com/", "rhubarb.foo.bar.com", False), 0283 ("http://foo.bar.com/", ".foo.bar.com", True), 0284 ("http://foo.bar.com/", "foo.bar.com", True), 0285 ("http://foo.bar.com/", ".bar.com", True), 0286 ("http://foo.bar.com/", "com", True), 0287 ("http://foo.com/", "rhubarb.foo.com", False), 0288 ("http://foo.com/", ".foo.com", True), 0289 ("http://foo.com/", "foo.com", True), 0290 ("http://foo.com/", "com", True), 0291 ("http://foo/", "rhubarb.foo", False), 0292 ("http://foo/", ".foo", True), 0293 ("http://foo/", "foo", True), 0294 ("http://foo/", "foo.local", True), 0295 ("http://foo/", ".local", True), 0296 ]: 0297 request = urllib2.Request(url) 0298 r = pol.domain_return_ok(domain, request) 0299 if ok: self.assert_(r) 0300 else: self.assert_(not r) 0301 0302 def test_missing_value(self): 0303 from cookielib import MozillaCookieJar, lwp_cookie_str 0304 0305 # missing = sign in Cookie: header is regarded by Mozilla as a missing 0306 # name, and by cookielib as a missing value 0307 filename = test_support.TESTFN 0308 c = MozillaCookieJar(filename) 0309 interact_netscape(c, "http://www.acme.com/", 'eggs') 0310 interact_netscape(c, "http://www.acme.com/", '"spam"; path=/foo/') 0311 cookie = c._cookies["www.acme.com"]["/"]["eggs"] 0312 self.assert_(cookie.value is None) 0313 self.assertEquals(cookie.name, "eggs") 0314 cookie = c._cookies["www.acme.com"]['/foo/']['"spam"'] 0315 self.assert_(cookie.value is None) 0316 self.assertEquals(cookie.name, '"spam"') 0317 self.assertEquals(lwp_cookie_str(cookie), ( 0318 r'"spam"; path="/foo/"; domain="www.acme.com"; ' 0319 'path_spec; discard; version=0')) 0320 old_str = repr(c) 0321 c.save(ignore_expires=True, ignore_discard=True) 0322 try: 0323 c = MozillaCookieJar(filename) 0324 c.revert(ignore_expires=True, ignore_discard=True) 0325 finally: 0326 os.unlink(c.filename) 0327 # cookies unchanged apart from lost info re. whether path was specified 0328 self.assertEquals( 0329 repr(c), 0330 re.sub("path_specified=%s" % True, "path_specified=%s" % False, 0331 old_str) 0332 ) 0333 self.assertEquals(interact_netscape(c, "http://www.acme.com/foo/"), 0334 '"spam"; eggs') 0335 0336 def test_ns_parser(self): 0337 from cookielib import CookieJar, DEFAULT_HTTP_PORT 0338 0339 c = CookieJar() 0340 interact_netscape(c, "http://www.acme.com/", 0341 'spam=eggs; DoMain=.acme.com; port; blArgh="feep"') 0342 interact_netscape(c, "http://www.acme.com/", 'ni=ni; port=80,8080') 0343 interact_netscape(c, "http://www.acme.com:80/", 'nini=ni') 0344 interact_netscape(c, "http://www.acme.com:80/", 'foo=bar; expires=') 0345 interact_netscape(c, "http://www.acme.com:80/", 'spam=eggs; ' 0346 'expires="Foo Bar 25 33:22:11 3022"') 0347 0348 cookie = c._cookies[".acme.com"]["/"]["spam"] 0349 self.assertEquals(cookie.domain, ".acme.com") 0350 self.assert_(cookie.domain_specified) 0351 self.assertEquals(cookie.port, DEFAULT_HTTP_PORT) 0352 self.assert_(not cookie.port_specified) 0353 # case is preserved 0354 self.assert_(cookie.has_nonstandard_attr("blArgh") and 0355 not cookie.has_nonstandard_attr("blargh")) 0356 0357 cookie = c._cookies["www.acme.com"]["/"]["ni"] 0358 self.assertEquals(cookie.domain, "www.acme.com") 0359 self.assert_(not cookie.domain_specified) 0360 self.assertEquals(cookie.port, "80,8080") 0361 self.assert_(cookie.port_specified) 0362 0363 cookie = c._cookies["www.acme.com"]["/"]["nini"] 0364 self.assert_(cookie.port is None) 0365 self.assert_(not cookie.port_specified) 0366 0367 # invalid expires should not cause cookie to be dropped 0368 foo = c._cookies["www.acme.com"]["/"]["foo"] 0369 spam = c._cookies["www.acme.com"]["/"]["foo"] 0370 self.assert_(foo.expires is None) 0371 self.assert_(spam.expires is None) 0372 0373 def test_expires(self): 0374 from cookielib import time2netscape, CookieJar 0375 0376 # if expires is in future, keep cookie... 0377 c = CookieJar() 0378 future = time2netscape(time.time()+3600) 0379 interact_netscape(c, "http://www.acme.com/", 'spam="bar"; expires=%s' % 0380 future) 0381 self.assertEquals(len(c), 1) 0382 now = time2netscape(time.time()-1) 0383 # ... and if in past or present, discard it 0384 interact_netscape(c, "http://www.acme.com/", 'foo="eggs"; expires=%s' % 0385 now) 0386 h = interact_netscape(c, "http://www.acme.com/") 0387 self.assertEquals(len(c), 1) 0388 self.assert_('spam="bar"' in h and "foo" not in h) 0389 0390 # max-age takes precedence over expires, and zero max-age is request to 0391 # delete both new cookie and any old matching cookie 0392 interact_netscape(c, "http://www.acme.com/", 'eggs="bar"; expires=%s' % 0393 future) 0394 interact_netscape(c, "http://www.acme.com/", 'bar="bar"; expires=%s' % 0395 future) 0396 self.assertEquals(len(c), 3) 0397 interact_netscape(c, "http://www.acme.com/", 'eggs="bar"; ' 0398 'expires=%s; max-age=0' % future) 0399 interact_netscape(c, "http://www.acme.com/", 'bar="bar"; ' 0400 'max-age=0; expires=%s' % future) 0401 h = interact_netscape(c, "http://www.acme.com/") 0402 self.assertEquals(len(c), 1) 0403 0404 # test expiry at end of session for cookies with no expires attribute 0405 interact_netscape(c, "http://www.rhubarb.net/", 'whum="fizz"') 0406 self.assertEquals(len(c), 2) 0407 c.clear_session_cookies() 0408 self.assertEquals(len(c), 1) 0409 self.assert_('spam="bar"' in h) 0410 0411 # XXX RFC 2965 expiry rules (some apply to V0 too) 0412 0413 def test_default_path(self): 0414 from cookielib import CookieJar, DefaultCookiePolicy 0415 0416 # RFC 2965 0417 pol = DefaultCookiePolicy(rfc2965=True) 0418 0419 c = CookieJar(pol) 0420 interact_2965(c, "http://www.acme.com/", 'spam="bar"; Version="1"') 0421 self.assert_("/" in c._cookies["www.acme.com"]) 0422 0423 c = CookieJar(pol) 0424 interact_2965(c, "http://www.acme.com/blah", 'eggs="bar"; Version="1"') 0425 self.assert_("/" in c._cookies["www.acme.com"]) 0426 0427 c = CookieJar(pol) 0428 interact_2965(c, "http://www.acme.com/blah/rhubarb", 0429 'eggs="bar"; Version="1"') 0430 self.assert_("/blah/" in c._cookies["www.acme.com"]) 0431 0432 c = CookieJar(pol) 0433 interact_2965(c, "http://www.acme.com/blah/rhubarb/", 0434 'eggs="bar"; Version="1"') 0435 self.assert_("/blah/rhubarb/" in c._cookies["www.acme.com"]) 0436 0437 # Netscape 0438 0439 c = CookieJar() 0440 interact_netscape(c, "http://www.acme.com/", 'spam="bar"') 0441 self.assert_("/" in c._cookies["www.acme.com"]) 0442 0443 c = CookieJar() 0444 interact_netscape(c, "http://www.acme.com/blah", 'eggs="bar"') 0445 self.assert_("/" in c._cookies["www.acme.com"]) 0446 0447 c = CookieJar() 0448 interact_netscape(c, "http://www.acme.com/blah/rhubarb", 'eggs="bar"') 0449 self.assert_("/blah" in c._cookies["www.acme.com"]) 0450 0451 c = CookieJar() 0452 interact_netscape(c, "http://www.acme.com/blah/rhubarb/", 'eggs="bar"') 0453 self.assert_("/blah/rhubarb" in c._cookies["www.acme.com"]) 0454 0455 def test_escape_path(self): 0456 from cookielib import escape_path 0457 cases = [ 0458 # quoted safe 0459 ("/foo%2f/bar", "/foo%2F/bar"), 0460 ("/foo%2F/bar", "/foo%2F/bar"), 0461 # quoted % 0462 ("/foo%%/bar", "/foo%%/bar"), 0463 # quoted unsafe 0464 ("/fo%19o/bar", "/fo%19o/bar"), 0465 ("/fo%7do/bar", "/fo%7Do/bar"), 0466 # unquoted safe 0467 ("/foo/bar&", "/foo/bar&"), 0468 ("/foo//bar", "/foo//bar"), 0469 ("\176/foo/bar", "\176/foo/bar"), 0470 # unquoted unsafe 0471 ("/foo\031/bar", "/foo%19/bar"), 0472 ("/\175foo/bar", "/%7Dfoo/bar"), 0473 # unicode 0474 (u"/foo/bar\uabcd", "/foo/bar%EA%AF%8D"), # UTF-8 encoded 0475 ] 0476 for arg, result in cases: 0477 self.assertEquals(escape_path(arg), result) 0478 0479 def test_request_path(self): 0480 from urllib2 import Request 0481 from cookielib import request_path 0482 # with parameters 0483 req = Request("http://www.example.com/rheum/rhaponicum;" 0484 "foo=bar;sing=song?apples=pears&spam=eggs#ni") 0485 self.assertEquals(request_path(req), "/rheum/rhaponicum;" 0486 "foo=bar;sing=song?apples=pears&spam=eggs#ni") 0487 # without parameters 0488 req = Request("http://www.example.com/rheum/rhaponicum?" 0489 "apples=pears&spam=eggs#ni") 0490 self.assertEquals(request_path(req), "/rheum/rhaponicum?" 0491 "apples=pears&spam=eggs#ni") 0492 # missing final slash 0493 req = Request("http://www.example.com") 0494 self.assertEquals(request_path(req), "/") 0495 0496 def test_request_port(self): 0497 from urllib2 import Request 0498 from cookielib import request_port, DEFAULT_HTTP_PORT 0499 req = Request("http://www.acme.com:1234/", 0500 headers={"Host": "www.acme.com:4321"}) 0501 self.assertEquals(request_port(req), "1234") 0502 req = Request("http://www.acme.com/", 0503 headers={"Host": "www.acme.com:4321"}) 0504 self.assertEquals(request_port(req), DEFAULT_HTTP_PORT) 0505 0506 def test_request_host(self): 0507 from urllib2 import Request 0508 from cookielib import request_host 0509 # this request is illegal (RFC2616, 14.2.3) 0510 req = Request("http://1.1.1.1/", 0511 headers={"Host": "www.acme.com:80"}) 0512 # libwww-perl wants this response, but that seems wrong (RFC 2616, 0513 # section 5.2, point 1., and RFC 2965 section 1, paragraph 3) 0514 #self.assertEquals(request_host(req), "www.acme.com") 0515 self.assertEquals(request_host(req), "1.1.1.1") 0516 req = Request("http://www.acme.com/", 0517 headers={"Host": "irrelevant.com"}) 0518 self.assertEquals(request_host(req), "www.acme.com") 0519 # not actually sure this one is valid Request object, so maybe should 0520 # remove test for no host in url in request_host function? 0521 req = Request("/resource.html", 0522 headers={"Host": "www.acme.com"}) 0523 self.assertEquals(request_host(req), "www.acme.com") 0524 # port shouldn't be in request-host 0525 req = Request("http://www.acme.com:2345/resource.html", 0526 headers={"Host": "www.acme.com:5432"}) 0527 self.assertEquals(request_host(req), "www.acme.com") 0528 0529 def test_is_HDN(self): 0530 from cookielib import is_HDN 0531 self.assert_(is_HDN("foo.bar.com")) 0532 self.assert_(is_HDN("1foo2.3bar4.5com")) 0533 self.assert_(not is_HDN("192.168.1.1")) 0534 self.assert_(not is_HDN("")) 0535 self.assert_(not is_HDN(".")) 0536 self.assert_(not is_HDN(".foo.bar.com")) 0537 self.assert_(not is_HDN("..foo")) 0538 self.assert_(not is_HDN("foo.")) 0539 0540 def test_reach(self): 0541 from cookielib import reach 0542 self.assertEquals(reach("www.acme.com"), ".acme.com") 0543 self.assertEquals(reach("acme.com"), "acme.com") 0544 self.assertEquals(reach("acme.local"), ".local") 0545 self.assertEquals(reach(".local"), ".local") 0546 self.assertEquals(reach(".com"), ".com") 0547 self.assertEquals(reach("."), ".") 0548 self.assertEquals(reach(""), "") 0549 self.assertEquals(reach("192.168.0.1"), "192.168.0.1") 0550 0551 def test_domain_match(self): 0552 from cookielib import domain_match, user_domain_match 0553 self.assert_(domain_match("192.168.1.1", "192.168.1.1")) 0554 self.assert_(not domain_match("192.168.1.1", ".168.1.1")) 0555 self.assert_(domain_match("x.y.com", "x.Y.com")) 0556 self.assert_(domain_match("x.y.com", ".Y.com")) 0557 self.assert_(not domain_match("x.y.com", "Y.com")) 0558 self.assert_(domain_match("a.b.c.com", ".c.com")) 0559 self.assert_(not domain_match(".c.com", "a.b.c.com")) 0560 self.assert_(domain_match("example.local", ".local")) 0561 self.assert_(not domain_match("blah.blah", "")) 0562 self.assert_(not domain_match("", ".rhubarb.rhubarb")) 0563 self.assert_(domain_match("", "")) 0564 0565 self.assert_(user_domain_match("acme.com", "acme.com")) 0566 self.assert_(not user_domain_match("acme.com", ".acme.com")) 0567 self.assert_(user_domain_match("rhubarb.acme.com", ".acme.com")) 0568 self.assert_(user_domain_match("www.rhubarb.acme.com", ".acme.com")) 0569 self.assert_(user_domain_match("x.y.com", "x.Y.com")) 0570 self.assert_(user_domain_match("x.y.com", ".Y.com")) 0571 self.assert_(not user_domain_match("x.y.com", "Y.com")) 0572 self.assert_(user_domain_match("y.com", "Y.com")) 0573 self.assert_(not user_domain_match(".y.com", "Y.com")) 0574 self.assert_(user_domain_match(".y.com", ".Y.com")) 0575 self.assert_(user_domain_match("x.y.com", ".com")) 0576 self.assert_(not user_domain_match("x.y.com", "com")) 0577 self.assert_(not user_domain_match("x.y.com", "m")) 0578 self.assert_(not user_domain_match("x.y.com", ".m")) 0579 self.assert_(not user_domain_match("x.y.com", "")) 0580 self.assert_(not user_domain_match("x.y.com", ".")) 0581 self.assert_(user_domain_match("192.168.1.1", "192.168.1.1")) 0582 # not both HDNs, so must string-compare equal to match 0583 self.assert_(not user_domain_match("192.168.1.1", ".168.1.1")) 0584 self.assert_(not user_domain_match("192.168.1.1", ".")) 0585 # empty string is a special case 0586 self.assert_(not user_domain_match("192.168.1.1", "")) 0587 0588 def test_wrong_domain(self): 0589 # Cookies whose effective request-host name does not domain-match the 0590 # domain are rejected. 0591 0592 # XXX far from complete 0593 from cookielib import CookieJar 0594 c = CookieJar() 0595 interact_2965(c, "http://www.nasty.com/", 0596 'foo=bar; domain=friendly.org; Version="1"') 0597 self.assertEquals(len(c), 0) 0598 0599 def test_two_component_domain_ns(self): 0600 # Netscape: .www.bar.com, www.bar.com, .bar.com, bar.com, no domain 0601 # should all get accepted, as should .acme.com, acme.com and no domain 0602 # for 2-component domains like acme.com. 0603 from cookielib import CookieJar, DefaultCookiePolicy 0604 0605 c = CookieJar() 0606 0607 # two-component V0 domain is OK 0608 interact_netscape(c, "http://foo.net/", 'ns=bar') 0609 self.assertEquals(len(c), 1) 0610 self.assertEquals(c._cookies["foo.net"]["/"]["ns"].value, "bar") 0611 self.assertEquals(interact_netscape(c, "http://foo.net/"), "ns=bar") 0612 # *will* be returned to any other domain (unlike RFC 2965)... 0613 self.assertEquals(interact_netscape(c, "http://www.foo.net/"), 0614 "ns=bar") 0615 # ...unless requested otherwise 0616 pol = DefaultCookiePolicy( 0617 strict_ns_domain=DefaultCookiePolicy.DomainStrictNonDomain) 0618 c.set_policy(pol) 0619 self.assertEquals(interact_netscape(c, "http://www.foo.net/"), "") 0620 0621 # unlike RFC 2965, even explicit two-component domain is OK, 0622 # because .foo.net matches foo.net 0623 interact_netscape(c, "http://foo.net/foo/", 0624 'spam1=eggs; domain=foo.net') 0625 # even if starts with a dot -- in NS rules, .foo.net matches foo.net! 0626 interact_netscape(c, "http://foo.net/foo/bar/", 0627 'spam2=eggs; domain=.foo.net') 0628 self.assertEquals(len(c), 3) 0629 self.assertEquals(c._cookies[".foo.net"]["/foo"]["spam1"].value, 0630 "eggs") 0631 self.assertEquals(c._cookies[".foo.net"]["/foo/bar"]["spam2"].value, 0632 "eggs") 0633 self.assertEquals(interact_netscape(c, "http://foo.net/foo/bar/"), 0634 "spam2=eggs; spam1=eggs; ns=bar") 0635 0636 # top-level domain is too general 0637 interact_netscape(c, "http://foo.net/", 'nini="ni"; domain=.net') 0638 self.assertEquals(len(c), 3) 0639 0640 ## # Netscape protocol doesn't allow non-special top level domains (such 0641 ## # as co.uk) in the domain attribute unless there are at least three 0642 ## # dots in it. 0643 # Oh yes it does! Real implementations don't check this, and real 0644 # cookies (of course) rely on that behaviour. 0645 interact_netscape(c, "http://foo.co.uk", 'nasty=trick; domain=.co.uk') 0646 ## self.assertEquals(len(c), 2) 0647 self.assertEquals(len(c), 4) 0648 0649 def test_two_component_domain_rfc2965(self): 0650 from cookielib import CookieJar, DefaultCookiePolicy 0651 0652 pol = DefaultCookiePolicy(rfc2965=True) 0653 c = CookieJar(pol) 0654 0655 # two-component V1 domain is OK 0656 interact_2965(c, "http://foo.net/", 'foo=bar; Version="1"') 0657 self.assertEquals(len(c), 1) 0658 self.assertEquals(c._cookies["foo.net"]["/"]["foo"].value, "bar") 0659 self.assertEquals(interact_2965(c, "http://foo.net/"), 0660 "$Version=1; foo=bar") 0661 # won't be returned to any other domain (because domain was implied) 0662 self.assertEquals(interact_2965(c, "http://www.foo.net/"), "") 0663 0664 # unless domain is given explicitly, because then it must be 0665 # rewritten to start with a dot: foo.net --> .foo.net, which does 0666 # not domain-match foo.net 0667 interact_2965(c, "http://foo.net/foo", 0668 'spam=eggs; domain=foo.net; path=/foo; Version="1"') 0669 self.assertEquals(len(c), 1) 0670 self.assertEquals(interact_2965(c, "http://foo.net/foo"), 0671 "$Version=1; foo=bar") 0672 0673 # explicit foo.net from three-component domain www.foo.net *does* get 0674 # set, because .foo.net domain-matches .foo.net 0675 interact_2965(c, "http://www.foo.net/foo/", 0676 'spam=eggs; domain=foo.net; Version="1"') 0677 self.assertEquals(c._cookies[".foo.net"]["/foo/"]["spam"].value, 0678 "eggs") 0679 self.assertEquals(len(c), 2) 0680 self.assertEquals(interact_2965(c, "http://foo.net/foo/"), 0681 "$Version=1; foo=bar") 0682 self.assertEquals(interact_2965(c, "http://www.foo.net/foo/"), 0683 '$Version=1; spam=eggs; $Domain="foo.net"') 0684 0685 # top-level domain is too general 0686 interact_2965(c, "http://foo.net/", 0687 'ni="ni"; domain=".net"; Version="1"') 0688 self.assertEquals(len(c), 2) 0689 0690 # RFC 2965 doesn't require blocking this 0691 interact_2965(c, "http://foo.co.uk/", 0692 'nasty=trick; domain=.co.uk; Version="1"') 0693 self.assertEquals(len(c), 3) 0694 0695 def test_domain_allow(self): 0696 from cookielib import CookieJar, DefaultCookiePolicy 0697 from urllib2 import Request 0698 0699 c = CookieJar(policy=DefaultCookiePolicy( 0700 blocked_domains=["acme.com"], 0701 allowed_domains=["www.acme.com"])) 0702 0703 req = Request("http://acme.com/") 0704 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"] 0705 res = FakeResponse(headers, "http://acme.com/") 0706 c.extract_cookies(res, req) 0707 self.assertEquals(len(c), 0) 0708 0709 req = Request("http://www.acme.com/") 0710 res = FakeResponse(headers, "http://www.acme.com/") 0711 c.extract_cookies(res, req) 0712 self.assertEquals(len(c), 1) 0713 0714 req = Request("http://www.coyote.com/") 0715 res = FakeResponse(headers, "http://www.coyote.com/") 0716 c.extract_cookies(res, req) 0717 self.assertEquals(len(c), 1) 0718 0719 # set a cookie with non-allowed domain... 0720 req = Request("http://www.coyote.com/") 0721 res = FakeResponse(headers, "http://www.coyote.com/") 0722 cookies = c.make_cookies(res, req) 0723 c.set_cookie(cookies[0]) 0724 self.assertEquals(len(c), 2) 0725 # ... and check is doesn't get returned 0726 c.add_cookie_header(req) 0727 self.assert_(not req.has_header("Cookie")) 0728 0729 def test_domain_block(self): 0730 from cookielib import CookieJar, DefaultCookiePolicy 0731 from urllib2 import Request 0732 0733 pol = DefaultCookiePolicy( 0734 rfc2965=True, blocked_domains=[".acme.com"]) 0735 c = CookieJar(policy=pol) 0736 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"] 0737 0738 req = Request("http://www.acme.com/") 0739 res = FakeResponse(headers, "http://www.acme.com/") 0740 c.extract_cookies(res, req) 0741 self.assertEquals(len(c), 0) 0742 0743 p = pol.set_blocked_domains(["acme.com"]) 0744 c.extract_cookies(res, req) 0745 self.assertEquals(len(c), 1) 0746 0747 c.clear() 0748 req = Request("http://www.roadrunner.net/") 0749 res = FakeResponse(headers, "http://www.roadrunner.net/") 0750 c.extract_cookies(res, req) 0751 self.assertEquals(len(c), 1) 0752 req = Request("http://www.roadrunner.net/") 0753 c.add_cookie_header(req) 0754 self.assert_((req.has_header("Cookie") and 0755 req.has_header("Cookie2"))) 0756 0757 c.clear() 0758 pol.set_blocked_domains([".acme.com"]) 0759 c.extract_cookies(res, req) 0760 self.assertEquals(len(c), 1) 0761 0762 # set a cookie with blocked domain... 0763 req = Request("http://www.acme.com/") 0764 res = FakeResponse(headers, "http://www.acme.com/") 0765 cookies = c.make_cookies(res, req) 0766 c.set_cookie(cookies[0]) 0767 self.assertEquals(len(c), 2) 0768 # ... and check is doesn't get returned 0769 c.add_cookie_header(req) 0770 self.assert_(not req.has_header("Cookie")) 0771 0772 def test_secure(self): 0773 from cookielib import CookieJar, DefaultCookiePolicy 0774 0775 for ns in True, False: 0776 for whitespace in " ", "": 0777 c = CookieJar() 0778 if ns: 0779 pol = DefaultCookiePolicy(rfc2965=False) 0780 int = interact_netscape 0781 vs = "" 0782 else: 0783 pol = DefaultCookiePolicy(rfc2965=True) 0784 int = interact_2965 0785 vs = "; Version=1" 0786 c.set_policy(pol) 0787 url = "http://www.acme.com/" 0788 int(c, url, "foo1=bar%s%s" % (vs, whitespace)) 0789 int(c, url, "foo2=bar%s; secure%s" % (vs, whitespace)) 0790 self.assert_( 0791 not c._cookies["www.acme.com"]["/"]["foo1"].secure, 0792 "non-secure cookie registered secure") 0793 self.assert_( 0794 c._cookies["www.acme.com"]["/"]["foo2"].secure, 0795 "secure cookie registered non-secure") 0796 0797 def test_quote_cookie_value(self): 0798 from cookielib import CookieJar, DefaultCookiePolicy 0799 c = CookieJar(policy=DefaultCookiePolicy(rfc2965=True)) 0800 interact_2965(c, "http://www.acme.com/", r'foo=\b"a"r; Version=1') 0801 h = interact_2965(c, "http://www.acme.com/") 0802 self.assertEquals(h, r'$Version=1; foo=\\b\"a\"r') 0803 0804 def test_missing_final_slash(self): 0805 # Missing slash from request URL's abs_path should be assumed present. 0806 from cookielib import CookieJar, DefaultCookiePolicy 0807 from urllib2 import Request 0808 url = "http://www.acme.com" 0809 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 0810 interact_2965(c, url, "foo=bar; Version=1") 0811 req = Request(url) 0812 self.assertEquals(len(c), 1) 0813 c.add_cookie_header(req) 0814 self.assert_(req.has_header("Cookie")) 0815 0816 def test_domain_mirror(self): 0817 from cookielib import CookieJar, DefaultCookiePolicy 0818 0819 pol = DefaultCookiePolicy(rfc2965=True) 0820 0821 c = CookieJar(pol) 0822 url = "http://foo.bar.com/" 0823 interact_2965(c, url, "spam=eggs; Version=1") 0824 h = interact_2965(c, url) 0825 self.assert_("Domain" not in h, 0826 "absent domain returned with domain present") 0827 0828 c = CookieJar(pol) 0829 url = "http://foo.bar.com/" 0830 interact_2965(c, url, 'spam=eggs; Version=1; Domain=.bar.com') 0831 h = interact_2965(c, url) 0832 self.assert_('$Domain=".bar.com"' in h, "domain not returned") 0833 0834 c = CookieJar(pol) 0835 url = "http://foo.bar.com/" 0836 # note missing initial dot in Domain 0837 interact_2965(c, url, 'spam=eggs; Version=1; Domain=bar.com') 0838 h = interact_2965(c, url) 0839 self.assert_('$Domain="bar.com"' in h, "domain not returned") 0840 0841 def test_path_mirror(self): 0842 from cookielib import CookieJar, DefaultCookiePolicy 0843 0844 pol = DefaultCookiePolicy(rfc2965=True) 0845 0846 c = CookieJar(pol) 0847 url = "http://foo.bar.com/" 0848 interact_2965(c, url, "spam=eggs; Version=1") 0849 h = interact_2965(c, url) 0850 self.assert_("Path" not in h, 0851 "absent path returned with path present") 0852 0853 c = CookieJar(pol) 0854 url = "http://foo.bar.com/" 0855 interact_2965(c, url, 'spam=eggs; Version=1; Path=/') 0856 h = interact_2965(c, url) 0857 self.assert_('$Path="/"' in h, "path not returned") 0858 0859 def test_port_mirror(self): 0860 from cookielib import CookieJar, DefaultCookiePolicy 0861 0862 pol = DefaultCookiePolicy(rfc2965=True) 0863 0864 c = CookieJar(pol) 0865 url = "http://foo.bar.com/" 0866 interact_2965(c, url, "spam=eggs; Version=1") 0867 h = interact_2965(c, url) 0868 self.assert_("Port" not in h, 0869 "absent port returned with port present") 0870 0871 c = CookieJar(pol) 0872 url = "http://foo.bar.com/" 0873 interact_2965(c, url, "spam=eggs; Version=1; Port") 0874 h = interact_2965(c, url) 0875 self.assert_(re.search("\$Port([^=]|$)", h), 0876 "port with no value not returned with no value") 0877 0878 c = CookieJar(pol) 0879 url = "http://foo.bar.com/" 0880 interact_2965(c, url, 'spam=eggs; Version=1; Port="80"') 0881 h = interact_2965(c, url) 0882 self.assert_('$Port="80"' in h, 0883 "port with single value not returned with single value") 0884 0885 c = CookieJar(pol) 0886 url = "http://foo.bar.com/" 0887 interact_2965(c, url, 'spam=eggs; Version=1; Port="80,8080"') 0888 h = interact_2965(c, url) 0889 self.assert_('$Port="80,8080"' in h, 0890 "port with multiple values not returned with multiple " 0891 "values") 0892 0893 def test_no_return_comment(self): 0894 from cookielib import CookieJar, DefaultCookiePolicy 0895 0896 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 0897 url = "http://foo.bar.com/" 0898 interact_2965(c, url, 'spam=eggs; Version=1; ' 0899 'Comment="does anybody read these?"; ' 0900 'CommentURL="http://foo.bar.net/comment.html"') 0901 h = interact_2965(c, url) 0902 self.assert_( 0903 "Comment" not in h, 0904 "Comment or CommentURL cookie-attributes returned to server") 0905 0906 def test_Cookie_iterator(self): 0907 from cookielib import CookieJar, Cookie, DefaultCookiePolicy 0908 0909 cs = CookieJar(DefaultCookiePolicy(rfc2965=True)) 0910 # add some random cookies 0911 interact_2965(cs, "http://blah.spam.org/", 'foo=eggs; Version=1; ' 0912 'Comment="does anybody read these?"; ' 0913 'CommentURL="http://foo.bar.net/comment.html"') 0914 interact_netscape(cs, "http://www.acme.com/blah/", "spam=bar; secure") 0915 interact_2965(cs, "http://www.acme.com/blah/", 0916 "foo=bar; secure; Version=1") 0917 interact_2965(cs, "http://www.acme.com/blah/", 0918 "foo=bar; path=/; Version=1") 0919 interact_2965(cs, "http://www.sol.no", 0920 r'bang=wallop; version=1; domain=".sol.no"; ' 0921 r'port="90,100, 80,8080"; ' 0922 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "') 0923 0924 versions = [1, 1, 1, 0, 1] 0925 names = ["bang", "foo", "foo", "spam", "foo"] 0926 domains = [".sol.no", "blah.spam.org", "www.acme.com", 0927 "www.acme.com", "www.acme.com"] 0928 paths = ["/", "/", "/", "/blah", "/blah/"] 0929 0930 for i in range(4): 0931 i = 0 0932 for c in cs: 0933 self.assert_(isinstance(c, Cookie)) 0934 self.assertEquals(c.version, versions[i]) 0935 self.assertEquals(c.name, names[i]) 0936 self.assertEquals(c.domain, domains[i]) 0937 self.assertEquals(c.path, paths[i]) 0938 i = i + 1 0939 0940 def test_parse_ns_headers(self): 0941 from cookielib import parse_ns_headers 0942 0943 # missing domain value (invalid cookie) 0944 self.assertEquals( 0945 parse_ns_headers(["foo=bar; path=/; domain"]), 0946 [[("foo", "bar"), 0947 ("path", "/"), ("domain", None), ("version", "0")]] 0948 ) 0949 # invalid expires value 0950 self.assertEquals( 0951 parse_ns_headers(["foo=bar; expires=Foo Bar 12 33:22:11 2000"]), 0952 [[("foo", "bar"), ("expires", None), ("version", "0")]] 0953 ) 0954 # missing cookie value (valid cookie) 0955 self.assertEquals( 0956 parse_ns_headers(["foo"]), 0957 [[("foo", None), ("version", "0")]] 0958 ) 0959 # shouldn't add version if header is empty 0960 self.assertEquals(parse_ns_headers([""]), []) 0961 0962 def test_bad_cookie_header(self): 0963 0964 def cookiejar_from_cookie_headers(headers): 0965 from cookielib import CookieJar 0966 from urllib2 import Request 0967 c = CookieJar() 0968 req = Request("http://www.example.com/") 0969 r = FakeResponse(headers, "http://www.example.com/") 0970 c.extract_cookies(r, req) 0971 return c 0972 0973 # none of these bad headers should cause an exception to be raised 0974 for headers in [ 0975 ["Set-Cookie: "], # actually, nothing wrong with this 0976 ["Set-Cookie2: "], # ditto 0977 # missing domain value 0978 ["Set-Cookie2: a=foo; path=/; Version=1; domain"], 0979 # bad max-age 0980 ["Set-Cookie: b=foo; max-age=oops"], 0981 ]: 0982 c = cookiejar_from_cookie_headers(headers) 0983 # these bad cookies shouldn't be set 0984 self.assertEquals(len(c), 0) 0985 0986 # cookie with invalid expires is treated as session cookie 0987 headers = ["Set-Cookie: c=foo; expires=Foo Bar 12 33:22:11 2000"] 0988 c = cookiejar_from_cookie_headers(headers) 0989 cookie = c._cookies["www.example.com"]["/"]["c"] 0990 self.assert_(cookie.expires is None) 0991 0992 0993 class LWPCookieTests(TestCase): 0994 # Tests taken from libwww-perl, with a few modifications and additions. 0995 0996 def test_netscape_example_1(self): 0997 from cookielib import CookieJar, DefaultCookiePolicy 0998 from urllib2 import Request 0999 1000 #------------------------------------------------------------------- 1001 # First we check that it works for the original example at 1002 # http://www.netscape.com/newsref/std/cookie_spec.html 1003 1004 # Client requests a document, and receives in the response: 1005 # 1006 # Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT 1007 # 1008 # When client requests a URL in path "/" on this server, it sends: 1009 # 1010 # Cookie: CUSTOMER=WILE_E_COYOTE 1011 # 1012 # Client requests a document, and receives in the response: 1013 # 1014 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/ 1015 # 1016 # When client requests a URL in path "/" on this server, it sends: 1017 # 1018 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001 1019 # 1020 # Client receives: 1021 # 1022 # Set-Cookie: SHIPPING=FEDEX; path=/fo 1023 # 1024 # When client requests a URL in path "/" on this server, it sends: 1025 # 1026 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001 1027 # 1028 # When client requests a URL in path "/foo" on this server, it sends: 1029 # 1030 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX 1031 # 1032 # The last Cookie is buggy, because both specifications say that the 1033 # most specific cookie must be sent first. SHIPPING=FEDEX is the 1034 # most specific and should thus be first. 1035 1036 year_plus_one = time.localtime()[0] + 1 1037 1038 headers = [] 1039 1040 c = CookieJar(DefaultCookiePolicy(rfc2965 = True)) 1041 1042 #req = Request("http://1.1.1.1/", 1043 # headers={"Host": "www.acme.com:80"}) 1044 req = Request("http://www.acme.com:80/", 1045 headers={"Host": "www.acme.com:80"}) 1046 1047 headers.append( 1048 "Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/ ; " 1049 "expires=Wednesday, 09-Nov-%d 23:12:40 GMT" % year_plus_one) 1050 res = FakeResponse(headers, "http://www.acme.com/") 1051 c.extract_cookies(res, req) 1052 1053 req = Request("http://www.acme.com/") 1054 c.add_cookie_header(req) 1055 1056 self.assertEqual(req.get_header("Cookie"), "CUSTOMER=WILE_E_COYOTE") 1057 self.assertEqual(req.get_header("Cookie2"), '$Version="1"') 1058 1059 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/") 1060 res = FakeResponse(headers, "http://www.acme.com/") 1061 c.extract_cookies(res, req) 1062 1063 req = Request("http://www.acme.com/foo/bar") 1064 c.add_cookie_header(req) 1065 1066 h = req.get_header("Cookie") 1067 self.assert_("PART_NUMBER=ROCKET_LAUNCHER_0001" in h and 1068 "CUSTOMER=WILE_E_COYOTE" in h) 1069 1070 headers.append('Set-Cookie: SHIPPING=FEDEX; path=/foo') 1071 res = FakeResponse(headers, "http://www.acme.com") 1072 c.extract_cookies(res, req) 1073 1074 req = Request("http://www.acme.com/") 1075 c.add_cookie_header(req) 1076 1077 h = req.get_header("Cookie") 1078 self.assert_("PART_NUMBER=ROCKET_LAUNCHER_0001" in h and 1079 "CUSTOMER=WILE_E_COYOTE" in h and 1080 "SHIPPING=FEDEX" not in h) 1081 1082 req = Request("http://www.acme.com/foo/") 1083 c.add_cookie_header(req) 1084 1085 h = req.get_header("Cookie") 1086 self.assert_(("PART_NUMBER=ROCKET_LAUNCHER_0001" in h and 1087 "CUSTOMER=WILE_E_COYOTE" in h and 1088 h.startswith("SHIPPING=FEDEX;"))) 1089 1090 def test_netscape_example_2(self): 1091 from cookielib import CookieJar 1092 from urllib2 import Request 1093 1094 # Second Example transaction sequence: 1095 # 1096 # Assume all mappings from above have been cleared. 1097 # 1098 # Client receives: 1099 # 1100 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/ 1101 # 1102 # When client requests a URL in path "/" on this server, it sends: 1103 # 1104 # Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001 1105 # 1106 # Client receives: 1107 # 1108 # Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo 1109 # 1110 # When client requests a URL in path "/ammo" on this server, it sends: 1111 # 1112 # Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001 1113 # 1114 # NOTE: There are two name/value pairs named "PART_NUMBER" due to 1115 # the inheritance of the "/" mapping in addition to the "/ammo" mapping. 1116 1117 c = CookieJar() 1118 headers = [] 1119 1120 req = Request("http://www.acme.com/") 1121 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/") 1122 res = FakeResponse(headers, "http://www.acme.com/") 1123 1124 c.extract_cookies(res, req) 1125 1126 req = Request("http://www.acme.com/") 1127 c.add_cookie_header(req) 1128 1129 self.assertEquals(req.get_header("Cookie"), 1130 "PART_NUMBER=ROCKET_LAUNCHER_0001") 1131 1132 headers.append( 1133 "Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo") 1134 res = FakeResponse(headers, "http://www.acme.com/") 1135 c.extract_cookies(res, req) 1136 1137 req = Request("http://www.acme.com/ammo") 1138 c.add_cookie_header(req) 1139 1140 self.assert_(re.search(r"PART_NUMBER=RIDING_ROCKET_0023;\s*" 1141 "PART_NUMBER=ROCKET_LAUNCHER_0001", 1142 req.get_header("Cookie"))) 1143 1144 def test_ietf_example_1(self): 1145 from cookielib import CookieJar, DefaultCookiePolicy 1146 #------------------------------------------------------------------- 1147 # Then we test with the examples from draft-ietf-http-state-man-mec-03.txt 1148 # 1149 # 5. EXAMPLES 1150 1151 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 1152 1153 # 1154 # 5.1 Example 1 1155 # 1156 # Most detail of request and response headers has been omitted. Assume 1157 # the user agent has no stored cookies. 1158 # 1159 # 1. User Agent -> Server 1160 # 1161 # POST /acme/login HTTP/1.1 1162 # [form data] 1163 # 1164 # User identifies self via a form. 1165 # 1166 # 2. Server -> User Agent 1167 # 1168 # HTTP/1.1 200 OK 1169 # Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme" 1170 # 1171 # Cookie reflects user's identity. 1172 1173 cookie = interact_2965( 1174 c, 'http://www.acme.com/acme/login', 1175 'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"') 1176 self.assert_(not cookie) 1177 1178 # 1179 # 3. User Agent -> Server 1180 # 1181 # POST /acme/pickitem HTTP/1.1 1182 # Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme" 1183 # [form data] 1184 # 1185 # User selects an item for ``shopping basket.'' 1186 # 1187 # 4. Server -> User Agent 1188 # 1189 # HTTP/1.1 200 OK 1190 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1"; 1191 # Path="/acme" 1192 # 1193 # Shopping basket contains an item. 1194 1195 cookie = interact_2965(c, 'http://www.acme.com/acme/pickitem', 1196 'Part_Number="Rocket_Launcher_0001"; ' 1197 'Version="1"; Path="/acme"'); 1198 self.assert_(re.search( 1199 r'^\$Version="?1"?; Customer="?WILE_E_COYOTE"?; \$Path="/acme"$', 1200 cookie)) 1201 1202 # 1203 # 5. User Agent -> Server 1204 # 1205 # POST /acme/shipping HTTP/1.1 1206 # Cookie: $Version="1"; 1207 # Customer="WILE_E_COYOTE"; $Path="/acme"; 1208 # Part_Number="Rocket_Launcher_0001"; $Path="/acme" 1209 # [form data] 1210 # 1211 # User selects shipping method from form. 1212 # 1213 # 6. Server -> User Agent 1214 # 1215 # HTTP/1.1 200 OK 1216 # Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme" 1217 # 1218 # New cookie reflects shipping method. 1219 1220 cookie = interact_2965(c, "http://www.acme.com/acme/shipping", 1221 'Shipping="FedEx"; Version="1"; Path="/acme"') 1222 1223 self.assert_(re.search(r'^\$Version="?1"?;', cookie)) 1224 self.assert_(re.search(r'Part_Number="?Rocket_Launcher_0001"?;' 1225 '\s*\$Path="\/acme"', cookie)) 1226 self.assert_(re.search(r'Customer="?WILE_E_COYOTE"?;\s*\$Path="\/acme"', 1227 cookie)) 1228 1229 # 1230 # 7. User Agent -> Server 1231 # 1232 # POST /acme/process HTTP/1.1 1233 # Cookie: $Version="1"; 1234 # Customer="WILE_E_COYOTE"; $Path="/acme"; 1235 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"; 1236 # Shipping="FedEx"; $Path="/acme" 1237 # [form data] 1238 # 1239 # User chooses to process order. 1240 # 1241 # 8. Server -> User Agent 1242 # 1243 # HTTP/1.1 200 OK 1244 # 1245 # Transaction is complete. 1246 1247 cookie = interact_2965(c, "http://www.acme.com/acme/process") 1248 self.assert_( 1249 re.search(r'Shipping="?FedEx"?;\s*\$Path="\/acme"', cookie) and 1250 "WILE_E_COYOTE" in cookie) 1251 1252 # 1253 # The user agent makes a series of requests on the origin server, after 1254 # each of which it receives a new cookie. All the cookies have the same 1255 # Path attribute and (default) domain. Because the request URLs all have 1256 # /acme as a prefix, and that matches the Path attribute, each request 1257 # contains all the cookies received so far. 1258 1259 def test_ietf_example_2(self): 1260 from cookielib import CookieJar, DefaultCookiePolicy 1261 1262 # 5.2 Example 2 1263 # 1264 # This example illustrates the effect of the Path attribute. All detail 1265 # of request and response headers has been omitted. Assume the user agent 1266 # has no stored cookies. 1267 1268 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 1269 1270 # Imagine the user agent has received, in response to earlier requests, 1271 # the response headers 1272 # 1273 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1"; 1274 # Path="/acme" 1275 # 1276 # and 1277 # 1278 # Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1"; 1279 # Path="/acme/ammo" 1280 1281 interact_2965( 1282 c, "http://www.acme.com/acme/ammo/specific", 1283 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"', 1284 'Part_Number="Riding_Rocket_0023"; Version="1"; Path="/acme/ammo"') 1285 1286 # A subsequent request by the user agent to the (same) server for URLs of 1287 # the form /acme/ammo/... would include the following request header: 1288 # 1289 # Cookie: $Version="1"; 1290 # Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo"; 1291 # Part_Number="Rocket_Launcher_0001"; $Path="/acme" 1292 # 1293 # Note that the NAME=VALUE pair for the cookie with the more specific Path 1294 # attribute, /acme/ammo, comes before the one with the less specific Path 1295 # attribute, /acme. Further note that the same cookie name appears more 1296 # than once. 1297 1298 cookie = interact_2965(c, "http://www.acme.com/acme/ammo/...") 1299 self.assert_( 1300 re.search(r"Riding_Rocket_0023.*Rocket_Launcher_0001", cookie)) 1301 1302 # A subsequent request by the user agent to the (same) server for a URL of 1303 # the form /acme/parts/ would include the following request header: 1304 # 1305 # Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme" 1306 # 1307 # Here, the second cookie's Path attribute /acme/ammo is not a prefix of 1308 # the request URL, /acme/parts/, so the cookie does not get forwarded to 1309 # the server. 1310 1311 cookie = interact_2965(c, "http://www.acme.com/acme/parts/") 1312 self.assert_("Rocket_Launcher_0001" in cookie and 1313 "Riding_Rocket_0023" not in cookie) 1314 1315 def test_rejection(self): 1316 # Test rejection of Set-Cookie2 responses based on domain, path, port. 1317 from cookielib import DefaultCookiePolicy, LWPCookieJar 1318 1319 pol = DefaultCookiePolicy(rfc2965=True) 1320 1321 c = LWPCookieJar(policy=pol) 1322 1323 max_age = "max-age=3600" 1324 1325 # illegal domain (no embedded dots) 1326 cookie = interact_2965(c, "http://www.acme.com", 1327 'foo=bar; domain=".com"; version=1') 1328 self.assert_(not c) 1329 1330 # legal domain 1331 cookie = interact_2965(c, "http://www.acme.com", 1332 'ping=pong; domain="acme.com"; version=1') 1333 self.assertEquals(len(c), 1) 1334 1335 # illegal domain (host prefix "www.a" contains a dot) 1336 cookie = interact_2965(c, "http://www.a.acme.com", 1337 'whiz=bang; domain="acme.com"; version=1') 1338 self.assertEquals(len(c), 1) 1339 1340 # legal domain 1341 cookie = interact_2965(c, "http://www.a.acme.com", 1342 'wow=flutter; domain=".a.acme.com"; version=1') 1343 self.assertEquals(len(c), 2) 1344 1345 # can't partially match an IP-address 1346 cookie = interact_2965(c, "http://125.125.125.125", 1347 'zzzz=ping; domain="125.125.125"; version=1') 1348 self.assertEquals(len(c), 2) 1349 1350 # illegal path (must be prefix of request path) 1351 cookie = interact_2965(c, "http://www.sol.no", 1352 'blah=rhubarb; domain=".sol.no"; path="/foo"; ' 1353 'version=1') 1354 self.assertEquals(len(c), 2) 1355 1356 # legal path 1357 cookie = interact_2965(c, "http://www.sol.no/foo/bar", 1358 'bing=bong; domain=".sol.no"; path="/foo"; ' 1359 'version=1') 1360 self.assertEquals(len(c), 3) 1361 1362 # illegal port (request-port not in list) 1363 cookie = interact_2965(c, "http://www.sol.no", 1364 'whiz=ffft; domain=".sol.no"; port="90,100"; ' 1365 'version=1') 1366 self.assertEquals(len(c), 3) 1367 1368 # legal port 1369 cookie = interact_2965( 1370 c, "http://www.sol.no", 1371 r'bang=wallop; version=1; domain=".sol.no"; ' 1372 r'port="90,100, 80,8080"; ' 1373 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "') 1374 self.assertEquals(len(c), 4) 1375 1376 # port attribute without any value (current port) 1377 cookie = interact_2965(c, "http://www.sol.no", 1378 'foo9=bar; version=1; domain=".sol.no"; port; ' 1379 'max-age=100;') 1380 self.assertEquals(len(c), 5) 1381 1382 # encoded path 1383 # LWP has this test, but unescaping allowed path characters seems 1384 # like a bad idea, so I think this should fail: 1385 ## cookie = interact_2965(c, "http://www.sol.no/foo/", 1386 ## r'foo8=bar; version=1; path="/%66oo"') 1387 # but this is OK, because '<' is not an allowed HTTP URL path 1388 # character: 1389 cookie = interact_2965(c, "http://www.sol.no/<oo/", 1390 r'foo8=bar; version=1; path="/%3coo"') 1391 self.assertEquals(len(c), 6) 1392 1393 # save and restore 1394 filename = test_support.TESTFN 1395 1396 try: 1397 c.save(filename, ignore_discard=True) 1398 old = repr(c) 1399 1400 c = LWPCookieJar(policy=pol) 1401 c.load(filename, ignore_discard=True) 1402 finally: 1403 try: os.unlink(filename) 1404 except OSError: pass 1405 1406 self.assertEquals(old, repr(c)) 1407 1408 def test_url_encoding(self): 1409 # Try some URL encodings of the PATHs. 1410 # (the behaviour here has changed from libwww-perl) 1411 from cookielib import CookieJar, DefaultCookiePolicy 1412 1413 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 1414 interact_2965(c, "http://www.acme.com/foo%2f%25/%3c%3c%0Anew%E5/%E5", 1415 "foo = bar; version = 1") 1416 1417 cookie = interact_2965( 1418 c, "http://www.acme.com/foo%2f%25/<<%0anewå/æøå", 1419 'bar=baz; path="/foo/"; version=1'); 1420 version_re = re.compile(r'^\$version=\"?1\"?', re.I) 1421 self.assert_("foo=bar" in cookie and version_re.search(cookie)) 1422 1423 cookie = interact_2965( 1424 c, "http://www.acme.com/foo/%25/<<%0anewå/æøå") 1425 self.assert_(not cookie) 1426 1427 # unicode URL doesn't raise exception 1428 cookie = interact_2965(c, u"http://www.acme.com/\xfc") 1429 1430 def test_mozilla(self): 1431 # Save / load Mozilla/Netscape cookie file format. 1432 from cookielib import MozillaCookieJar, DefaultCookiePolicy 1433 1434 year_plus_one = time.localtime()[0] + 1 1435 1436 filename = test_support.TESTFN 1437 1438 c = MozillaCookieJar(filename, 1439 policy=DefaultCookiePolicy(rfc2965=True)) 1440 interact_2965(c, "http://www.acme.com/", 1441 "foo1=bar; max-age=100; Version=1") 1442 interact_2965(c, "http://www.acme.com/", 1443 'foo2=bar; port="80"; max-age=100; Discard; Version=1') 1444 interact_2965(c, "http://www.acme.com/", "foo3=bar; secure; Version=1") 1445 1446 expires = "expires=09-Nov-%d 23:12:40 GMT" % (year_plus_one,) 1447 interact_netscape(c, "http://www.foo.com/", 1448 "fooa=bar; %s" % expires) 1449 interact_netscape(c, "http://www.foo.com/", 1450 "foob=bar; Domain=.foo.com; %s" % expires) 1451 interact_netscape(c, "http://www.foo.com/", 1452 "fooc=bar; Domain=www.foo.com; %s" % expires) 1453 1454 def save_and_restore(cj, ignore_discard): 1455 try: 1456 cj.save(ignore_discard=ignore_discard) 1457 new_c = MozillaCookieJar(filename, 1458 DefaultCookiePolicy(rfc2965=True)) 1459 new_c.load(ignore_discard=ignore_discard) 1460 finally: 1461 try: os.unlink(filename) 1462 except OSError: pass 1463 return new_c 1464 1465 new_c = save_and_restore(c, True) 1466 self.assertEquals(len(new_c), 6) # none discarded 1467 self.assert_("name='foo1', value='bar'" in repr(new_c)) 1468 1469 new_c = save_and_restore(c, False) 1470 self.assertEquals(len(new_c), 4) # 2 of them discarded on save 1471 self.assert_("name='foo1', value='bar'" in repr(new_c)) 1472 1473 def test_netscape_misc(self): 1474 # Some additional Netscape cookies tests. 1475 from cookielib import CookieJar 1476 from urllib2 import Request 1477 1478 c = CookieJar() 1479 headers = [] 1480 req = Request("http://foo.bar.acme.com/foo") 1481 1482 # Netscape allows a host part that contains dots 1483 headers.append("Set-Cookie: Customer=WILE_E_COYOTE; domain=.acme.com") 1484 res = FakeResponse(headers, "http://www.acme.com/foo") 1485 c.extract_cookies(res, req) 1486 1487 # and that the domain is the same as the host without adding a leading 1488 # dot to the domain. Should not quote even if strange chars are used 1489 # in the cookie value. 1490 headers.append("Set-Cookie: PART_NUMBER=3,4; domain=foo.bar.acme.com") 1491 res = FakeResponse(headers, "http://www.acme.com/foo") 1492 c.extract_cookies(res, req) 1493 1494 req = Request("http://foo.bar.acme.com/foo") 1495 c.add_cookie_header(req) 1496 self.assert_( 1497 "PART_NUMBER=3,4" in req.get_header("Cookie") and 1498 "Customer=WILE_E_COYOTE" in req.get_header("Cookie")) 1499 1500 def test_intranet_domains_2965(self): 1501 # Test handling of local intranet hostnames without a dot. 1502 from cookielib import CookieJar, DefaultCookiePolicy 1503 1504 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 1505 interact_2965(c, "http://example/", 1506 "foo1=bar; PORT; Discard; Version=1;") 1507 cookie = interact_2965(c, "http://example/", 1508 'foo2=bar; domain=".local"; Version=1') 1509 self.assert_("foo1=bar" in cookie) 1510 1511 interact_2965(c, "http://example/", 'foo3=bar; Version=1') 1512 cookie = interact_2965(c, "http://example/") 1513 self.assert_("foo2=bar" in cookie and len(c) == 3) 1514 1515 def test_intranet_domains_ns(self): 1516 from cookielib import CookieJar, DefaultCookiePolicy 1517 1518 c = CookieJar(DefaultCookiePolicy(rfc2965 = False)) 1519 interact_netscape(c, "http://example/", "foo1=bar") 1520 cookie = interact_netscape(c, "http://example/", 1521 'foo2=bar; domain=.local') 1522 self.assertEquals(len(c), 2) 1523 self.assert_("foo1=bar" in cookie) 1524 1525 cookie = interact_netscape(c, "http://example/") 1526 self.assert_("foo2=bar" in cookie) 1527 self.assertEquals(len(c), 2) 1528 1529 def test_empty_path(self): 1530 from cookielib import CookieJar, DefaultCookiePolicy 1531 from urllib2 import Request 1532 1533 # Test for empty path 1534 # Broken web-server ORION/1.3.38 returns to the client response like 1535 # 1536 # Set-Cookie: JSESSIONID=ABCDERANDOM123; Path= 1537 # 1538 # ie. with Path set to nothing. 1539 # In this case, extract_cookies() must set cookie to / (root) 1540 c = CookieJar(DefaultCookiePolicy(rfc2965 = True)) 1541 headers = [] 1542 1543 req = Request("http://www.ants.com/") 1544 headers.append("Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=") 1545 res = FakeResponse(headers, "http://www.ants.com/") 1546 c.extract_cookies(res, req) 1547 1548 req = Request("http://www.ants.com/") 1549 c.add_cookie_header(req) 1550 1551 self.assertEquals(req.get_header("Cookie"), 1552 "JSESSIONID=ABCDERANDOM123") 1553 self.assertEquals(req.get_header("Cookie2"), '$Version="1"') 1554 1555 # missing path in the request URI 1556 req = Request("http://www.ants.com:8080") 1557 c.add_cookie_header(req) 1558 1559 self.assertEquals(req.get_header("Cookie"), 1560 "JSESSIONID=ABCDERANDOM123") 1561 self.assertEquals(req.get_header("Cookie2"), '$Version="1"') 1562 1563 def test_session_cookies(self): 1564 from cookielib import CookieJar 1565 from urllib2 import Request 1566 1567 year_plus_one = time.localtime()[0] + 1 1568 1569 # Check session cookies are deleted properly by 1570 # CookieJar.clear_session_cookies method 1571 1572 req = Request('http://www.perlmeister.com/scripts') 1573 headers = [] 1574 headers.append("Set-Cookie: s1=session;Path=/scripts") 1575 headers.append("Set-Cookie: p1=perm; Domain=.perlmeister.com;" 1576 "Path=/;expires=Fri, 02-Feb-%d 23:24:20 GMT" % 1577 year_plus_one) 1578 headers.append("Set-Cookie: p2=perm;Path=/;expires=Fri, " 1579 "02-Feb-%d 23:24:20 GMT" % year_plus_one) 1580 headers.append("Set-Cookie: s2=session;Path=/scripts;" 1581 "Domain=.perlmeister.com") 1582 headers.append('Set-Cookie2: s3=session;Version=1;Discard;Path="/"') 1583 res = FakeResponse(headers, 'http://www.perlmeister.com/scripts') 1584 1585 c = CookieJar() 1586 c.extract_cookies(res, req) 1587 # How many session/permanent cookies do we have? 1588 counter = {"session_after": 0, 1589 "perm_after": 0, 1590 "session_before": 0, 1591 "perm_before": 0} 1592 for cookie in c: 1593 key = "%s_before" % cookie.value 1594 counter[key] = counter[key] + 1 1595 c.clear_session_cookies() 1596 # How many now? 1597 for cookie in c: 1598 key = "%s_after" % cookie.value 1599 counter[key] = counter[key] + 1 1600 1601 self.assert_(not ( 1602 # a permanent cookie got lost accidently 1603 counter["perm_after"] != counter["perm_before"] or 1604 # a session cookie hasn't been cleared 1605 counter["session_after"] != 0 or 1606 # we didn't have session cookies in the first place 1607 counter["session_before"] == 0)) 1608 1609 1610 def test_main(verbose=None): 1611 from test import test_sets 1612 test_support.run_unittest( 1613 DateTimeTests, 1614 HeaderTests, 1615 CookieTests, 1616 LWPCookieTests, 1617 ) 1618 1619 if __name__ == "__main__": 1620 test_main(verbose=True) 1621
Generated by PyXR 0.9.4