test_cookielib.py revision b1d867f14965e2369d31a3fcdab5bca34b4d81b4
1# -*- coding: latin-1 -*- 2"""Tests for cookielib.py.""" 3 4import cookielib 5import os 6import re 7import time 8 9from unittest import TestCase 10 11from test import test_support 12 13 14class DateTimeTests(TestCase): 15 16 def test_time2isoz(self): 17 from cookielib import time2isoz 18 19 base = 1019227000 20 day = 24*3600 21 self.assertEqual(time2isoz(base), "2002-04-19 14:36:40Z") 22 self.assertEqual(time2isoz(base+day), "2002-04-20 14:36:40Z") 23 self.assertEqual(time2isoz(base+2*day), "2002-04-21 14:36:40Z") 24 self.assertEqual(time2isoz(base+3*day), "2002-04-22 14:36:40Z") 25 26 az = time2isoz() 27 bz = time2isoz(500000) 28 for text in (az, bz): 29 self.assertRegexpMatches(text, 30 r"^\d{4}-\d\d-\d\d \d\d:\d\d:\d\dZ$", 31 "bad time2isoz format: %s %s" % (az, bz)) 32 33 def test_http2time(self): 34 from cookielib import http2time 35 36 def parse_date(text): 37 return time.gmtime(http2time(text))[:6] 38 39 self.assertEqual(parse_date("01 Jan 2001"), (2001, 1, 1, 0, 0, 0.0)) 40 41 # this test will break around year 2070 42 self.assertEqual(parse_date("03-Feb-20"), (2020, 2, 3, 0, 0, 0.0)) 43 44 # this test will break around year 2048 45 self.assertEqual(parse_date("03-Feb-98"), (1998, 2, 3, 0, 0, 0.0)) 46 47 def test_http2time_formats(self): 48 from cookielib import http2time, time2isoz 49 50 # test http2time for supported dates. Test cases with 2 digit year 51 # will probably break in year 2044. 52 tests = [ 53 'Thu, 03 Feb 1994 00:00:00 GMT', # proposed new HTTP format 54 'Thursday, 03-Feb-94 00:00:00 GMT', # old rfc850 HTTP format 55 'Thursday, 03-Feb-1994 00:00:00 GMT', # broken rfc850 HTTP format 56 57 '03 Feb 1994 00:00:00 GMT', # HTTP format (no weekday) 58 '03-Feb-94 00:00:00 GMT', # old rfc850 (no weekday) 59 '03-Feb-1994 00:00:00 GMT', # broken rfc850 (no weekday) 60 '03-Feb-1994 00:00 GMT', # broken rfc850 (no weekday, no seconds) 61 '03-Feb-1994 00:00', # broken rfc850 (no weekday, no seconds, no tz) 62 63 '03-Feb-94', # old rfc850 HTTP format (no weekday, no time) 64 '03-Feb-1994', # broken rfc850 HTTP format (no weekday, no time) 65 '03 Feb 1994', # proposed new HTTP format (no weekday, no time) 66 67 # A few tests with extra space at various places 68 ' 03 Feb 1994 0:00 ', 69 ' 03-Feb-1994 ', 70 ] 71 72 test_t = 760233600 # assume broken POSIX counting of seconds 73 result = time2isoz(test_t) 74 expected = "1994-02-03 00:00:00Z" 75 self.assertEqual(result, expected, 76 "%s => '%s' (%s)" % (test_t, result, expected)) 77 78 for s in tests: 79 self.assertEqual(http2time(s), test_t, s) 80 self.assertEqual(http2time(s.lower()), test_t, s.lower()) 81 self.assertEqual(http2time(s.upper()), test_t, s.upper()) 82 83 def test_http2time_garbage(self): 84 from cookielib import http2time 85 86 for test in [ 87 '', 88 'Garbage', 89 'Mandag 16. September 1996', 90 '01-00-1980', 91 '01-13-1980', 92 '00-01-1980', 93 '32-01-1980', 94 '01-01-1980 25:00:00', 95 '01-01-1980 00:61:00', 96 '01-01-1980 00:00:62', 97 ]: 98 self.assertTrue(http2time(test) is None, 99 "http2time(%s) is not None\n" 100 "http2time(test) %s" % (test, http2time(test)) 101 ) 102 103 104class HeaderTests(TestCase): 105 106 def test_parse_ns_headers_expires(self): 107 from cookielib import parse_ns_headers 108 109 # quotes should be stripped 110 expected = [[('foo', 'bar'), ('expires', 2209069412L), ('version', '0')]] 111 for hdr in [ 112 'foo=bar; expires=01 Jan 2040 22:23:32 GMT', 113 'foo=bar; expires="01 Jan 2040 22:23:32 GMT"', 114 ]: 115 self.assertEqual(parse_ns_headers([hdr]), expected) 116 117 def test_parse_ns_headers_version(self): 118 from cookielib import parse_ns_headers 119 120 # quotes should be stripped 121 expected = [[('foo', 'bar'), ('version', '1')]] 122 for hdr in [ 123 'foo=bar; version="1"', 124 'foo=bar; Version="1"', 125 ]: 126 self.assertEqual(parse_ns_headers([hdr]), expected) 127 128 def test_parse_ns_headers_special_names(self): 129 # names such as 'expires' are not special in first name=value pair 130 # of Set-Cookie: header 131 from cookielib import parse_ns_headers 132 133 # Cookie with name 'expires' 134 hdr = 'expires=01 Jan 2040 22:23:32 GMT' 135 expected = [[("expires", "01 Jan 2040 22:23:32 GMT"), ("version", "0")]] 136 self.assertEqual(parse_ns_headers([hdr]), expected) 137 138 def test_join_header_words(self): 139 from cookielib import join_header_words 140 141 joined = join_header_words([[("foo", None), ("bar", "baz")]]) 142 self.assertEqual(joined, "foo; bar=baz") 143 144 self.assertEqual(join_header_words([[]]), "") 145 146 def test_split_header_words(self): 147 from cookielib import split_header_words 148 149 tests = [ 150 ("foo", [[("foo", None)]]), 151 ("foo=bar", [[("foo", "bar")]]), 152 (" foo ", [[("foo", None)]]), 153 (" foo= ", [[("foo", "")]]), 154 (" foo=", [[("foo", "")]]), 155 (" foo= ; ", [[("foo", "")]]), 156 (" foo= ; bar= baz ", [[("foo", ""), ("bar", "baz")]]), 157 ("foo=bar bar=baz", [[("foo", "bar"), ("bar", "baz")]]), 158 # doesn't really matter if this next fails, but it works ATM 159 ("foo= bar=baz", [[("foo", "bar=baz")]]), 160 ("foo=bar;bar=baz", [[("foo", "bar"), ("bar", "baz")]]), 161 ('foo bar baz', [[("foo", None), ("bar", None), ("baz", None)]]), 162 ("a, b, c", [[("a", None)], [("b", None)], [("c", None)]]), 163 (r'foo; bar=baz, spam=, foo="\,\;\"", bar= ', 164 [[("foo", None), ("bar", "baz")], 165 [("spam", "")], [("foo", ',;"')], [("bar", "")]]), 166 ] 167 168 for arg, expect in tests: 169 try: 170 result = split_header_words([arg]) 171 except: 172 import traceback, StringIO 173 f = StringIO.StringIO() 174 traceback.print_exc(None, f) 175 result = "(error -- traceback follows)\n\n%s" % f.getvalue() 176 self.assertEqual(result, expect, """ 177When parsing: '%s' 178Expected: '%s' 179Got: '%s' 180""" % (arg, expect, result)) 181 182 def test_roundtrip(self): 183 from cookielib import split_header_words, join_header_words 184 185 tests = [ 186 ("foo", "foo"), 187 ("foo=bar", "foo=bar"), 188 (" foo ", "foo"), 189 ("foo=", 'foo=""'), 190 ("foo=bar bar=baz", "foo=bar; bar=baz"), 191 ("foo=bar;bar=baz", "foo=bar; bar=baz"), 192 ('foo bar baz', "foo; bar; baz"), 193 (r'foo="\"" bar="\\"', r'foo="\""; bar="\\"'), 194 ('foo,,,bar', 'foo, bar'), 195 ('foo=bar,bar=baz', 'foo=bar, bar=baz'), 196 197 ('text/html; charset=iso-8859-1', 198 'text/html; charset="iso-8859-1"'), 199 200 ('foo="bar"; port="80,81"; discard, bar=baz', 201 'foo=bar; port="80,81"; discard, bar=baz'), 202 203 (r'Basic realm="\"foo\\\\bar\""', 204 r'Basic; realm="\"foo\\\\bar\""') 205 ] 206 207 for arg, expect in tests: 208 input = split_header_words([arg]) 209 res = join_header_words(input) 210 self.assertEqual(res, expect, """ 211When parsing: '%s' 212Expected: '%s' 213Got: '%s' 214Input was: '%s' 215""" % (arg, expect, res, input)) 216 217 218class FakeResponse: 219 def __init__(self, headers=[], url=None): 220 """ 221 headers: list of RFC822-style 'Key: value' strings 222 """ 223 import mimetools, StringIO 224 f = StringIO.StringIO("\n".join(headers)) 225 self._headers = mimetools.Message(f) 226 self._url = url 227 def info(self): return self._headers 228 229def interact_2965(cookiejar, url, *set_cookie_hdrs): 230 return _interact(cookiejar, url, set_cookie_hdrs, "Set-Cookie2") 231 232def interact_netscape(cookiejar, url, *set_cookie_hdrs): 233 return _interact(cookiejar, url, set_cookie_hdrs, "Set-Cookie") 234 235def _interact(cookiejar, url, set_cookie_hdrs, hdr_name): 236 """Perform a single request / response cycle, returning Cookie: header.""" 237 from urllib2 import Request 238 req = Request(url) 239 cookiejar.add_cookie_header(req) 240 cookie_hdr = req.get_header("Cookie", "") 241 headers = [] 242 for hdr in set_cookie_hdrs: 243 headers.append("%s: %s" % (hdr_name, hdr)) 244 res = FakeResponse(headers, url) 245 cookiejar.extract_cookies(res, req) 246 return cookie_hdr 247 248 249class FileCookieJarTests(TestCase): 250 def test_lwp_valueless_cookie(self): 251 # cookies with no value should be saved and loaded consistently 252 from cookielib import LWPCookieJar 253 filename = test_support.TESTFN 254 c = LWPCookieJar() 255 interact_netscape(c, "http://www.acme.com/", 'boo') 256 self.assertEqual(c._cookies["www.acme.com"]["/"]["boo"].value, None) 257 try: 258 c.save(filename, ignore_discard=True) 259 c = LWPCookieJar() 260 c.load(filename, ignore_discard=True) 261 finally: 262 try: os.unlink(filename) 263 except OSError: pass 264 self.assertEqual(c._cookies["www.acme.com"]["/"]["boo"].value, None) 265 266 def test_bad_magic(self): 267 from cookielib import LWPCookieJar, MozillaCookieJar, LoadError 268 # IOErrors (eg. file doesn't exist) are allowed to propagate 269 filename = test_support.TESTFN 270 for cookiejar_class in LWPCookieJar, MozillaCookieJar: 271 c = cookiejar_class() 272 try: 273 c.load(filename="for this test to work, a file with this " 274 "filename should not exist") 275 except IOError, exc: 276 # exactly IOError, not LoadError 277 self.assertEqual(exc.__class__, IOError) 278 else: 279 self.fail("expected IOError for invalid filename") 280 # Invalid contents of cookies file (eg. bad magic string) 281 # causes a LoadError. 282 try: 283 f = open(filename, "w") 284 f.write("oops\n") 285 for cookiejar_class in LWPCookieJar, MozillaCookieJar: 286 c = cookiejar_class() 287 self.assertRaises(LoadError, c.load, filename) 288 finally: 289 try: os.unlink(filename) 290 except OSError: pass 291 292class CookieTests(TestCase): 293 # XXX 294 # Get rid of string comparisons where not actually testing str / repr. 295 # .clear() etc. 296 # IP addresses like 50 (single number, no dot) and domain-matching 297 # functions (and is_HDN)? See draft RFC 2965 errata. 298 # Strictness switches 299 # is_third_party() 300 # unverifiability / third-party blocking 301 # Netscape cookies work the same as RFC 2965 with regard to port. 302 # Set-Cookie with negative max age. 303 # If turn RFC 2965 handling off, Set-Cookie2 cookies should not clobber 304 # Set-Cookie cookies. 305 # Cookie2 should be sent if *any* cookies are not V1 (ie. V0 OR V2 etc.). 306 # Cookies (V1 and V0) with no expiry date should be set to be discarded. 307 # RFC 2965 Quoting: 308 # Should accept unquoted cookie-attribute values? check errata draft. 309 # Which are required on the way in and out? 310 # Should always return quoted cookie-attribute values? 311 # Proper testing of when RFC 2965 clobbers Netscape (waiting for errata). 312 # Path-match on return (same for V0 and V1). 313 # RFC 2965 acceptance and returning rules 314 # Set-Cookie2 without version attribute is rejected. 315 316 # Netscape peculiarities list from Ronald Tschalar. 317 # The first two still need tests, the rest are covered. 318## - Quoting: only quotes around the expires value are recognized as such 319## (and yes, some folks quote the expires value); quotes around any other 320## value are treated as part of the value. 321## - White space: white space around names and values is ignored 322## - Default path: if no path parameter is given, the path defaults to the 323## path in the request-uri up to, but not including, the last '/'. Note 324## that this is entirely different from what the spec says. 325## - Commas and other delimiters: Netscape just parses until the next ';'. 326## This means it will allow commas etc inside values (and yes, both 327## commas and equals are commonly appear in the cookie value). This also 328## means that if you fold multiple Set-Cookie header fields into one, 329## comma-separated list, it'll be a headache to parse (at least my head 330## starts hurting every time I think of that code). 331## - Expires: You'll get all sorts of date formats in the expires, 332## including emtpy expires attributes ("expires="). Be as flexible as you 333## can, and certainly don't expect the weekday to be there; if you can't 334## parse it, just ignore it and pretend it's a session cookie. 335## - Domain-matching: Netscape uses the 2-dot rule for _all_ domains, not 336## just the 7 special TLD's listed in their spec. And folks rely on 337## that... 338 339 def test_domain_return_ok(self): 340 # test optimization: .domain_return_ok() should filter out most 341 # domains in the CookieJar before we try to access them (because that 342 # may require disk access -- in particular, with MSIECookieJar) 343 # This is only a rough check for performance reasons, so it's not too 344 # critical as long as it's sufficiently liberal. 345 import cookielib, urllib2 346 pol = cookielib.DefaultCookiePolicy() 347 for url, domain, ok in [ 348 ("http://foo.bar.com/", "blah.com", False), 349 ("http://foo.bar.com/", "rhubarb.blah.com", False), 350 ("http://foo.bar.com/", "rhubarb.foo.bar.com", False), 351 ("http://foo.bar.com/", ".foo.bar.com", True), 352 ("http://foo.bar.com/", "foo.bar.com", True), 353 ("http://foo.bar.com/", ".bar.com", True), 354 ("http://foo.bar.com/", "com", True), 355 ("http://foo.com/", "rhubarb.foo.com", False), 356 ("http://foo.com/", ".foo.com", True), 357 ("http://foo.com/", "foo.com", True), 358 ("http://foo.com/", "com", True), 359 ("http://foo/", "rhubarb.foo", False), 360 ("http://foo/", ".foo", True), 361 ("http://foo/", "foo", True), 362 ("http://foo/", "foo.local", True), 363 ("http://foo/", ".local", True), 364 ]: 365 request = urllib2.Request(url) 366 r = pol.domain_return_ok(domain, request) 367 if ok: self.assertTrue(r) 368 else: self.assertFalse(r) 369 370 def test_missing_value(self): 371 from cookielib import MozillaCookieJar, lwp_cookie_str 372 373 # missing = sign in Cookie: header is regarded by Mozilla as a missing 374 # name, and by cookielib as a missing value 375 filename = test_support.TESTFN 376 c = MozillaCookieJar(filename) 377 interact_netscape(c, "http://www.acme.com/", 'eggs') 378 interact_netscape(c, "http://www.acme.com/", '"spam"; path=/foo/') 379 cookie = c._cookies["www.acme.com"]["/"]["eggs"] 380 self.assertIsNone(cookie.value) 381 self.assertEqual(cookie.name, "eggs") 382 cookie = c._cookies["www.acme.com"]['/foo/']['"spam"'] 383 self.assertIsNone(cookie.value) 384 self.assertEqual(cookie.name, '"spam"') 385 self.assertEqual(lwp_cookie_str(cookie), ( 386 r'"spam"; path="/foo/"; domain="www.acme.com"; ' 387 'path_spec; discard; version=0')) 388 old_str = repr(c) 389 c.save(ignore_expires=True, ignore_discard=True) 390 try: 391 c = MozillaCookieJar(filename) 392 c.revert(ignore_expires=True, ignore_discard=True) 393 finally: 394 os.unlink(c.filename) 395 # cookies unchanged apart from lost info re. whether path was specified 396 self.assertEqual( 397 repr(c), 398 re.sub("path_specified=%s" % True, "path_specified=%s" % False, 399 old_str) 400 ) 401 self.assertEqual(interact_netscape(c, "http://www.acme.com/foo/"), 402 '"spam"; eggs') 403 404 def test_rfc2109_handling(self): 405 # RFC 2109 cookies are handled as RFC 2965 or Netscape cookies, 406 # dependent on policy settings 407 from cookielib import CookieJar, DefaultCookiePolicy 408 409 for rfc2109_as_netscape, rfc2965, version in [ 410 # default according to rfc2965 if not explicitly specified 411 (None, False, 0), 412 (None, True, 1), 413 # explicit rfc2109_as_netscape 414 (False, False, None), # version None here means no cookie stored 415 (False, True, 1), 416 (True, False, 0), 417 (True, True, 0), 418 ]: 419 policy = DefaultCookiePolicy( 420 rfc2109_as_netscape=rfc2109_as_netscape, 421 rfc2965=rfc2965) 422 c = CookieJar(policy) 423 interact_netscape(c, "http://www.example.com/", "ni=ni; Version=1") 424 try: 425 cookie = c._cookies["www.example.com"]["/"]["ni"] 426 except KeyError: 427 self.assertIsNone(version) # didn't expect a stored cookie 428 else: 429 self.assertEqual(cookie.version, version) 430 # 2965 cookies are unaffected 431 interact_2965(c, "http://www.example.com/", 432 "foo=bar; Version=1") 433 if rfc2965: 434 cookie2965 = c._cookies["www.example.com"]["/"]["foo"] 435 self.assertEqual(cookie2965.version, 1) 436 437 def test_ns_parser(self): 438 from cookielib import CookieJar, DEFAULT_HTTP_PORT 439 440 c = CookieJar() 441 interact_netscape(c, "http://www.acme.com/", 442 'spam=eggs; DoMain=.acme.com; port; blArgh="feep"') 443 interact_netscape(c, "http://www.acme.com/", 'ni=ni; port=80,8080') 444 interact_netscape(c, "http://www.acme.com:80/", 'nini=ni') 445 interact_netscape(c, "http://www.acme.com:80/", 'foo=bar; expires=') 446 interact_netscape(c, "http://www.acme.com:80/", 'spam=eggs; ' 447 'expires="Foo Bar 25 33:22:11 3022"') 448 interact_netscape(c, 'http://www.acme.com/', 'fortytwo=') 449 interact_netscape(c, 'http://www.acme.com/', '=unladenswallow') 450 interact_netscape(c, 'http://www.acme.com/', 'holyhandgrenade') 451 452 cookie = c._cookies[".acme.com"]["/"]["spam"] 453 self.assertEqual(cookie.domain, ".acme.com") 454 self.assertTrue(cookie.domain_specified) 455 self.assertEqual(cookie.port, DEFAULT_HTTP_PORT) 456 self.assertFalse(cookie.port_specified) 457 # case is preserved 458 self.assertTrue(cookie.has_nonstandard_attr("blArgh")) 459 self.assertFalse(cookie.has_nonstandard_attr("blargh")) 460 461 cookie = c._cookies["www.acme.com"]["/"]["ni"] 462 self.assertEqual(cookie.domain, "www.acme.com") 463 self.assertFalse(cookie.domain_specified) 464 self.assertEqual(cookie.port, "80,8080") 465 self.assertTrue(cookie.port_specified) 466 467 cookie = c._cookies["www.acme.com"]["/"]["nini"] 468 self.assertIsNone(cookie.port) 469 self.assertFalse(cookie.port_specified) 470 471 # invalid expires should not cause cookie to be dropped 472 foo = c._cookies["www.acme.com"]["/"]["foo"] 473 spam = c._cookies["www.acme.com"]["/"]["foo"] 474 self.assertIsNone(foo.expires) 475 self.assertIsNone(spam.expires) 476 477 cookie = c._cookies['www.acme.com']['/']['fortytwo'] 478 self.assertIsNotNone(cookie.value) 479 self.assertEqual(cookie.value, '') 480 481 # there should be a distinction between a present but empty value 482 # (above) and a value that's entirely missing (below) 483 484 cookie = c._cookies['www.acme.com']['/']['holyhandgrenade'] 485 self.assertIsNone(cookie.value) 486 487 def test_ns_parser_special_names(self): 488 # names such as 'expires' are not special in first name=value pair 489 # of Set-Cookie: header 490 from cookielib import CookieJar 491 492 c = CookieJar() 493 interact_netscape(c, "http://www.acme.com/", 'expires=eggs') 494 interact_netscape(c, "http://www.acme.com/", 'version=eggs; spam=eggs') 495 496 cookies = c._cookies["www.acme.com"]["/"] 497 self.assertTrue('expires' in cookies) 498 self.assertTrue('version' in cookies) 499 500 def test_expires(self): 501 from cookielib import time2netscape, CookieJar 502 503 # if expires is in future, keep cookie... 504 c = CookieJar() 505 future = time2netscape(time.time()+3600) 506 interact_netscape(c, "http://www.acme.com/", 'spam="bar"; expires=%s' % 507 future) 508 self.assertEqual(len(c), 1) 509 now = time2netscape(time.time()-1) 510 # ... and if in past or present, discard it 511 interact_netscape(c, "http://www.acme.com/", 'foo="eggs"; expires=%s' % 512 now) 513 h = interact_netscape(c, "http://www.acme.com/") 514 self.assertEqual(len(c), 1) 515 self.assertTrue('spam="bar"' in h and "foo" not in h) 516 517 # max-age takes precedence over expires, and zero max-age is request to 518 # delete both new cookie and any old matching cookie 519 interact_netscape(c, "http://www.acme.com/", 'eggs="bar"; expires=%s' % 520 future) 521 interact_netscape(c, "http://www.acme.com/", 'bar="bar"; expires=%s' % 522 future) 523 self.assertEqual(len(c), 3) 524 interact_netscape(c, "http://www.acme.com/", 'eggs="bar"; ' 525 'expires=%s; max-age=0' % future) 526 interact_netscape(c, "http://www.acme.com/", 'bar="bar"; ' 527 'max-age=0; expires=%s' % future) 528 h = interact_netscape(c, "http://www.acme.com/") 529 self.assertEqual(len(c), 1) 530 531 # test expiry at end of session for cookies with no expires attribute 532 interact_netscape(c, "http://www.rhubarb.net/", 'whum="fizz"') 533 self.assertEqual(len(c), 2) 534 c.clear_session_cookies() 535 self.assertEqual(len(c), 1) 536 self.assertIn('spam="bar"', h) 537 538 # XXX RFC 2965 expiry rules (some apply to V0 too) 539 540 def test_default_path(self): 541 from cookielib import CookieJar, DefaultCookiePolicy 542 543 # RFC 2965 544 pol = DefaultCookiePolicy(rfc2965=True) 545 546 c = CookieJar(pol) 547 interact_2965(c, "http://www.acme.com/", 'spam="bar"; Version="1"') 548 self.assertIn("/", c._cookies["www.acme.com"]) 549 550 c = CookieJar(pol) 551 interact_2965(c, "http://www.acme.com/blah", 'eggs="bar"; Version="1"') 552 self.assertIn("/", c._cookies["www.acme.com"]) 553 554 c = CookieJar(pol) 555 interact_2965(c, "http://www.acme.com/blah/rhubarb", 556 'eggs="bar"; Version="1"') 557 self.assertIn("/blah/", c._cookies["www.acme.com"]) 558 559 c = CookieJar(pol) 560 interact_2965(c, "http://www.acme.com/blah/rhubarb/", 561 'eggs="bar"; Version="1"') 562 self.assertIn("/blah/rhubarb/", c._cookies["www.acme.com"]) 563 564 # Netscape 565 566 c = CookieJar() 567 interact_netscape(c, "http://www.acme.com/", 'spam="bar"') 568 self.assertIn("/", c._cookies["www.acme.com"]) 569 570 c = CookieJar() 571 interact_netscape(c, "http://www.acme.com/blah", 'eggs="bar"') 572 self.assertIn("/", c._cookies["www.acme.com"]) 573 574 c = CookieJar() 575 interact_netscape(c, "http://www.acme.com/blah/rhubarb", 'eggs="bar"') 576 self.assertIn("/blah", c._cookies["www.acme.com"]) 577 578 c = CookieJar() 579 interact_netscape(c, "http://www.acme.com/blah/rhubarb/", 'eggs="bar"') 580 self.assertIn("/blah/rhubarb", c._cookies["www.acme.com"]) 581 582 def test_default_path_with_query(self): 583 cj = cookielib.CookieJar() 584 uri = "http://example.com/?spam/eggs" 585 value = 'eggs="bar"' 586 interact_netscape(cj, uri, value) 587 # default path does not include query, so is "/", not "/?spam" 588 self.assertIn("/", cj._cookies["example.com"]) 589 # cookie is sent back to the same URI 590 self.assertEqual(interact_netscape(cj, uri), value) 591 592 def test_escape_path(self): 593 from cookielib import escape_path 594 cases = [ 595 # quoted safe 596 ("/foo%2f/bar", "/foo%2F/bar"), 597 ("/foo%2F/bar", "/foo%2F/bar"), 598 # quoted % 599 ("/foo%%/bar", "/foo%%/bar"), 600 # quoted unsafe 601 ("/fo%19o/bar", "/fo%19o/bar"), 602 ("/fo%7do/bar", "/fo%7Do/bar"), 603 # unquoted safe 604 ("/foo/bar&", "/foo/bar&"), 605 ("/foo//bar", "/foo//bar"), 606 ("\176/foo/bar", "\176/foo/bar"), 607 # unquoted unsafe 608 ("/foo\031/bar", "/foo%19/bar"), 609 ("/\175foo/bar", "/%7Dfoo/bar"), 610 # unicode 611 (u"/foo/bar\uabcd", "/foo/bar%EA%AF%8D"), # UTF-8 encoded 612 ] 613 for arg, result in cases: 614 self.assertEqual(escape_path(arg), result) 615 616 def test_request_path(self): 617 from urllib2 import Request 618 from cookielib import request_path 619 # with parameters 620 req = Request("http://www.example.com/rheum/rhaponticum;" 621 "foo=bar;sing=song?apples=pears&spam=eggs#ni") 622 self.assertEqual(request_path(req), 623 "/rheum/rhaponticum;foo=bar;sing=song") 624 # without parameters 625 req = Request("http://www.example.com/rheum/rhaponticum?" 626 "apples=pears&spam=eggs#ni") 627 self.assertEqual(request_path(req), "/rheum/rhaponticum") 628 # missing final slash 629 req = Request("http://www.example.com") 630 self.assertEqual(request_path(req), "/") 631 632 def test_request_port(self): 633 from urllib2 import Request 634 from cookielib import request_port, DEFAULT_HTTP_PORT 635 req = Request("http://www.acme.com:1234/", 636 headers={"Host": "www.acme.com:4321"}) 637 self.assertEqual(request_port(req), "1234") 638 req = Request("http://www.acme.com/", 639 headers={"Host": "www.acme.com:4321"}) 640 self.assertEqual(request_port(req), DEFAULT_HTTP_PORT) 641 642 def test_request_host(self): 643 from urllib2 import Request 644 from cookielib import request_host 645 # this request is illegal (RFC2616, 14.2.3) 646 req = Request("http://1.1.1.1/", 647 headers={"Host": "www.acme.com:80"}) 648 # libwww-perl wants this response, but that seems wrong (RFC 2616, 649 # section 5.2, point 1., and RFC 2965 section 1, paragraph 3) 650 #self.assertEqual(request_host(req), "www.acme.com") 651 self.assertEqual(request_host(req), "1.1.1.1") 652 req = Request("http://www.acme.com/", 653 headers={"Host": "irrelevant.com"}) 654 self.assertEqual(request_host(req), "www.acme.com") 655 # not actually sure this one is valid Request object, so maybe should 656 # remove test for no host in url in request_host function? 657 req = Request("/resource.html", 658 headers={"Host": "www.acme.com"}) 659 self.assertEqual(request_host(req), "www.acme.com") 660 # port shouldn't be in request-host 661 req = Request("http://www.acme.com:2345/resource.html", 662 headers={"Host": "www.acme.com:5432"}) 663 self.assertEqual(request_host(req), "www.acme.com") 664 665 def test_is_HDN(self): 666 from cookielib import is_HDN 667 self.assertTrue(is_HDN("foo.bar.com")) 668 self.assertTrue(is_HDN("1foo2.3bar4.5com")) 669 self.assertFalse(is_HDN("192.168.1.1")) 670 self.assertFalse(is_HDN("")) 671 self.assertFalse(is_HDN(".")) 672 self.assertFalse(is_HDN(".foo.bar.com")) 673 self.assertFalse(is_HDN("..foo")) 674 self.assertFalse(is_HDN("foo.")) 675 676 def test_reach(self): 677 from cookielib import reach 678 self.assertEqual(reach("www.acme.com"), ".acme.com") 679 self.assertEqual(reach("acme.com"), "acme.com") 680 self.assertEqual(reach("acme.local"), ".local") 681 self.assertEqual(reach(".local"), ".local") 682 self.assertEqual(reach(".com"), ".com") 683 self.assertEqual(reach("."), ".") 684 self.assertEqual(reach(""), "") 685 self.assertEqual(reach("192.168.0.1"), "192.168.0.1") 686 687 def test_domain_match(self): 688 from cookielib import domain_match, user_domain_match 689 self.assertTrue(domain_match("192.168.1.1", "192.168.1.1")) 690 self.assertFalse(domain_match("192.168.1.1", ".168.1.1")) 691 self.assertTrue(domain_match("x.y.com", "x.Y.com")) 692 self.assertTrue(domain_match("x.y.com", ".Y.com")) 693 self.assertFalse(domain_match("x.y.com", "Y.com")) 694 self.assertTrue(domain_match("a.b.c.com", ".c.com")) 695 self.assertFalse(domain_match(".c.com", "a.b.c.com")) 696 self.assertTrue(domain_match("example.local", ".local")) 697 self.assertFalse(domain_match("blah.blah", "")) 698 self.assertFalse(domain_match("", ".rhubarb.rhubarb")) 699 self.assertTrue(domain_match("", "")) 700 701 self.assertTrue(user_domain_match("acme.com", "acme.com")) 702 self.assertFalse(user_domain_match("acme.com", ".acme.com")) 703 self.assertTrue(user_domain_match("rhubarb.acme.com", ".acme.com")) 704 self.assertTrue(user_domain_match("www.rhubarb.acme.com", ".acme.com")) 705 self.assertTrue(user_domain_match("x.y.com", "x.Y.com")) 706 self.assertTrue(user_domain_match("x.y.com", ".Y.com")) 707 self.assertFalse(user_domain_match("x.y.com", "Y.com")) 708 self.assertTrue(user_domain_match("y.com", "Y.com")) 709 self.assertFalse(user_domain_match(".y.com", "Y.com")) 710 self.assertTrue(user_domain_match(".y.com", ".Y.com")) 711 self.assertTrue(user_domain_match("x.y.com", ".com")) 712 self.assertFalse(user_domain_match("x.y.com", "com")) 713 self.assertFalse(user_domain_match("x.y.com", "m")) 714 self.assertFalse(user_domain_match("x.y.com", ".m")) 715 self.assertFalse(user_domain_match("x.y.com", "")) 716 self.assertFalse(user_domain_match("x.y.com", ".")) 717 self.assertTrue(user_domain_match("192.168.1.1", "192.168.1.1")) 718 # not both HDNs, so must string-compare equal to match 719 self.assertFalse(user_domain_match("192.168.1.1", ".168.1.1")) 720 self.assertFalse(user_domain_match("192.168.1.1", ".")) 721 # empty string is a special case 722 self.assertFalse(user_domain_match("192.168.1.1", "")) 723 724 def test_wrong_domain(self): 725 # Cookies whose effective request-host name does not domain-match the 726 # domain are rejected. 727 728 # XXX far from complete 729 from cookielib import CookieJar 730 c = CookieJar() 731 interact_2965(c, "http://www.nasty.com/", 732 'foo=bar; domain=friendly.org; Version="1"') 733 self.assertEqual(len(c), 0) 734 735 def test_strict_domain(self): 736 # Cookies whose domain is a country-code tld like .co.uk should 737 # not be set if CookiePolicy.strict_domain is true. 738 from cookielib import CookieJar, DefaultCookiePolicy 739 740 cp = DefaultCookiePolicy(strict_domain=True) 741 cj = CookieJar(policy=cp) 742 interact_netscape(cj, "http://example.co.uk/", 'no=problemo') 743 interact_netscape(cj, "http://example.co.uk/", 744 'okey=dokey; Domain=.example.co.uk') 745 self.assertEqual(len(cj), 2) 746 for pseudo_tld in [".co.uk", ".org.za", ".tx.us", ".name.us"]: 747 interact_netscape(cj, "http://example.%s/" % pseudo_tld, 748 'spam=eggs; Domain=.co.uk') 749 self.assertEqual(len(cj), 2) 750 751 def test_two_component_domain_ns(self): 752 # Netscape: .www.bar.com, www.bar.com, .bar.com, bar.com, no domain 753 # should all get accepted, as should .acme.com, acme.com and no domain 754 # for 2-component domains like acme.com. 755 from cookielib import CookieJar, DefaultCookiePolicy 756 757 c = CookieJar() 758 759 # two-component V0 domain is OK 760 interact_netscape(c, "http://foo.net/", 'ns=bar') 761 self.assertEqual(len(c), 1) 762 self.assertEqual(c._cookies["foo.net"]["/"]["ns"].value, "bar") 763 self.assertEqual(interact_netscape(c, "http://foo.net/"), "ns=bar") 764 # *will* be returned to any other domain (unlike RFC 2965)... 765 self.assertEqual(interact_netscape(c, "http://www.foo.net/"), 766 "ns=bar") 767 # ...unless requested otherwise 768 pol = DefaultCookiePolicy( 769 strict_ns_domain=DefaultCookiePolicy.DomainStrictNonDomain) 770 c.set_policy(pol) 771 self.assertEqual(interact_netscape(c, "http://www.foo.net/"), "") 772 773 # unlike RFC 2965, even explicit two-component domain is OK, 774 # because .foo.net matches foo.net 775 interact_netscape(c, "http://foo.net/foo/", 776 'spam1=eggs; domain=foo.net') 777 # even if starts with a dot -- in NS rules, .foo.net matches foo.net! 778 interact_netscape(c, "http://foo.net/foo/bar/", 779 'spam2=eggs; domain=.foo.net') 780 self.assertEqual(len(c), 3) 781 self.assertEqual(c._cookies[".foo.net"]["/foo"]["spam1"].value, 782 "eggs") 783 self.assertEqual(c._cookies[".foo.net"]["/foo/bar"]["spam2"].value, 784 "eggs") 785 self.assertEqual(interact_netscape(c, "http://foo.net/foo/bar/"), 786 "spam2=eggs; spam1=eggs; ns=bar") 787 788 # top-level domain is too general 789 interact_netscape(c, "http://foo.net/", 'nini="ni"; domain=.net') 790 self.assertEqual(len(c), 3) 791 792## # Netscape protocol doesn't allow non-special top level domains (such 793## # as co.uk) in the domain attribute unless there are at least three 794## # dots in it. 795 # Oh yes it does! Real implementations don't check this, and real 796 # cookies (of course) rely on that behaviour. 797 interact_netscape(c, "http://foo.co.uk", 'nasty=trick; domain=.co.uk') 798## self.assertEqual(len(c), 2) 799 self.assertEqual(len(c), 4) 800 801 def test_two_component_domain_rfc2965(self): 802 from cookielib import CookieJar, DefaultCookiePolicy 803 804 pol = DefaultCookiePolicy(rfc2965=True) 805 c = CookieJar(pol) 806 807 # two-component V1 domain is OK 808 interact_2965(c, "http://foo.net/", 'foo=bar; Version="1"') 809 self.assertEqual(len(c), 1) 810 self.assertEqual(c._cookies["foo.net"]["/"]["foo"].value, "bar") 811 self.assertEqual(interact_2965(c, "http://foo.net/"), 812 "$Version=1; foo=bar") 813 # won't be returned to any other domain (because domain was implied) 814 self.assertEqual(interact_2965(c, "http://www.foo.net/"), "") 815 816 # unless domain is given explicitly, because then it must be 817 # rewritten to start with a dot: foo.net --> .foo.net, which does 818 # not domain-match foo.net 819 interact_2965(c, "http://foo.net/foo", 820 'spam=eggs; domain=foo.net; path=/foo; Version="1"') 821 self.assertEqual(len(c), 1) 822 self.assertEqual(interact_2965(c, "http://foo.net/foo"), 823 "$Version=1; foo=bar") 824 825 # explicit foo.net from three-component domain www.foo.net *does* get 826 # set, because .foo.net domain-matches .foo.net 827 interact_2965(c, "http://www.foo.net/foo/", 828 'spam=eggs; domain=foo.net; Version="1"') 829 self.assertEqual(c._cookies[".foo.net"]["/foo/"]["spam"].value, 830 "eggs") 831 self.assertEqual(len(c), 2) 832 self.assertEqual(interact_2965(c, "http://foo.net/foo/"), 833 "$Version=1; foo=bar") 834 self.assertEqual(interact_2965(c, "http://www.foo.net/foo/"), 835 '$Version=1; spam=eggs; $Domain="foo.net"') 836 837 # top-level domain is too general 838 interact_2965(c, "http://foo.net/", 839 'ni="ni"; domain=".net"; Version="1"') 840 self.assertEqual(len(c), 2) 841 842 # RFC 2965 doesn't require blocking this 843 interact_2965(c, "http://foo.co.uk/", 844 'nasty=trick; domain=.co.uk; Version="1"') 845 self.assertEqual(len(c), 3) 846 847 def test_domain_allow(self): 848 from cookielib import CookieJar, DefaultCookiePolicy 849 from urllib2 import Request 850 851 c = CookieJar(policy=DefaultCookiePolicy( 852 blocked_domains=["acme.com"], 853 allowed_domains=["www.acme.com"])) 854 855 req = Request("http://acme.com/") 856 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"] 857 res = FakeResponse(headers, "http://acme.com/") 858 c.extract_cookies(res, req) 859 self.assertEqual(len(c), 0) 860 861 req = Request("http://www.acme.com/") 862 res = FakeResponse(headers, "http://www.acme.com/") 863 c.extract_cookies(res, req) 864 self.assertEqual(len(c), 1) 865 866 req = Request("http://www.coyote.com/") 867 res = FakeResponse(headers, "http://www.coyote.com/") 868 c.extract_cookies(res, req) 869 self.assertEqual(len(c), 1) 870 871 # set a cookie with non-allowed domain... 872 req = Request("http://www.coyote.com/") 873 res = FakeResponse(headers, "http://www.coyote.com/") 874 cookies = c.make_cookies(res, req) 875 c.set_cookie(cookies[0]) 876 self.assertEqual(len(c), 2) 877 # ... and check is doesn't get returned 878 c.add_cookie_header(req) 879 self.assertFalse(req.has_header("Cookie")) 880 881 def test_domain_block(self): 882 from cookielib import CookieJar, DefaultCookiePolicy 883 from urllib2 import Request 884 885 pol = DefaultCookiePolicy( 886 rfc2965=True, blocked_domains=[".acme.com"]) 887 c = CookieJar(policy=pol) 888 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"] 889 890 req = Request("http://www.acme.com/") 891 res = FakeResponse(headers, "http://www.acme.com/") 892 c.extract_cookies(res, req) 893 self.assertEqual(len(c), 0) 894 895 p = pol.set_blocked_domains(["acme.com"]) 896 c.extract_cookies(res, req) 897 self.assertEqual(len(c), 1) 898 899 c.clear() 900 req = Request("http://www.roadrunner.net/") 901 res = FakeResponse(headers, "http://www.roadrunner.net/") 902 c.extract_cookies(res, req) 903 self.assertEqual(len(c), 1) 904 req = Request("http://www.roadrunner.net/") 905 c.add_cookie_header(req) 906 self.assertTrue(req.has_header("Cookie")) 907 self.assertTrue(req.has_header("Cookie2")) 908 909 c.clear() 910 pol.set_blocked_domains([".acme.com"]) 911 c.extract_cookies(res, req) 912 self.assertEqual(len(c), 1) 913 914 # set a cookie with blocked domain... 915 req = Request("http://www.acme.com/") 916 res = FakeResponse(headers, "http://www.acme.com/") 917 cookies = c.make_cookies(res, req) 918 c.set_cookie(cookies[0]) 919 self.assertEqual(len(c), 2) 920 # ... and check is doesn't get returned 921 c.add_cookie_header(req) 922 self.assertFalse(req.has_header("Cookie")) 923 924 def test_secure(self): 925 from cookielib import CookieJar, DefaultCookiePolicy 926 927 for ns in True, False: 928 for whitespace in " ", "": 929 c = CookieJar() 930 if ns: 931 pol = DefaultCookiePolicy(rfc2965=False) 932 int = interact_netscape 933 vs = "" 934 else: 935 pol = DefaultCookiePolicy(rfc2965=True) 936 int = interact_2965 937 vs = "; Version=1" 938 c.set_policy(pol) 939 url = "http://www.acme.com/" 940 int(c, url, "foo1=bar%s%s" % (vs, whitespace)) 941 int(c, url, "foo2=bar%s; secure%s" % (vs, whitespace)) 942 self.assertFalse( 943 c._cookies["www.acme.com"]["/"]["foo1"].secure, 944 "non-secure cookie registered secure") 945 self.assertTrue( 946 c._cookies["www.acme.com"]["/"]["foo2"].secure, 947 "secure cookie registered non-secure") 948 949 def test_quote_cookie_value(self): 950 from cookielib import CookieJar, DefaultCookiePolicy 951 c = CookieJar(policy=DefaultCookiePolicy(rfc2965=True)) 952 interact_2965(c, "http://www.acme.com/", r'foo=\b"a"r; Version=1') 953 h = interact_2965(c, "http://www.acme.com/") 954 self.assertEqual(h, r'$Version=1; foo=\\b\"a\"r') 955 956 def test_missing_final_slash(self): 957 # Missing slash from request URL's abs_path should be assumed present. 958 from cookielib import CookieJar, DefaultCookiePolicy 959 from urllib2 import Request 960 url = "http://www.acme.com" 961 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 962 interact_2965(c, url, "foo=bar; Version=1") 963 req = Request(url) 964 self.assertEqual(len(c), 1) 965 c.add_cookie_header(req) 966 self.assertTrue(req.has_header("Cookie")) 967 968 def test_domain_mirror(self): 969 from cookielib import CookieJar, DefaultCookiePolicy 970 971 pol = DefaultCookiePolicy(rfc2965=True) 972 973 c = CookieJar(pol) 974 url = "http://foo.bar.com/" 975 interact_2965(c, url, "spam=eggs; Version=1") 976 h = interact_2965(c, url) 977 self.assertNotIn("Domain", h, 978 "absent domain returned with domain present") 979 980 c = CookieJar(pol) 981 url = "http://foo.bar.com/" 982 interact_2965(c, url, 'spam=eggs; Version=1; Domain=.bar.com') 983 h = interact_2965(c, url) 984 self.assertIn('$Domain=".bar.com"', h, "domain not returned") 985 986 c = CookieJar(pol) 987 url = "http://foo.bar.com/" 988 # note missing initial dot in Domain 989 interact_2965(c, url, 'spam=eggs; Version=1; Domain=bar.com') 990 h = interact_2965(c, url) 991 self.assertIn('$Domain="bar.com"', h, "domain not returned") 992 993 def test_path_mirror(self): 994 from cookielib import CookieJar, DefaultCookiePolicy 995 996 pol = DefaultCookiePolicy(rfc2965=True) 997 998 c = CookieJar(pol) 999 url = "http://foo.bar.com/" 1000 interact_2965(c, url, "spam=eggs; Version=1") 1001 h = interact_2965(c, url) 1002 self.assertNotIn("Path", h, "absent path returned with path present") 1003 1004 c = CookieJar(pol) 1005 url = "http://foo.bar.com/" 1006 interact_2965(c, url, 'spam=eggs; Version=1; Path=/') 1007 h = interact_2965(c, url) 1008 self.assertIn('$Path="/"', h, "path not returned") 1009 1010 def test_port_mirror(self): 1011 from cookielib import CookieJar, DefaultCookiePolicy 1012 1013 pol = DefaultCookiePolicy(rfc2965=True) 1014 1015 c = CookieJar(pol) 1016 url = "http://foo.bar.com/" 1017 interact_2965(c, url, "spam=eggs; Version=1") 1018 h = interact_2965(c, url) 1019 self.assertNotIn("Port", h, "absent port returned with port present") 1020 1021 c = CookieJar(pol) 1022 url = "http://foo.bar.com/" 1023 interact_2965(c, url, "spam=eggs; Version=1; Port") 1024 h = interact_2965(c, url) 1025 self.assertRegexpMatches(h, "\$Port([^=]|$)", 1026 "port with no value not returned with no value") 1027 1028 c = CookieJar(pol) 1029 url = "http://foo.bar.com/" 1030 interact_2965(c, url, 'spam=eggs; Version=1; Port="80"') 1031 h = interact_2965(c, url) 1032 self.assertIn('$Port="80"', h, 1033 "port with single value not returned with single value") 1034 1035 c = CookieJar(pol) 1036 url = "http://foo.bar.com/" 1037 interact_2965(c, url, 'spam=eggs; Version=1; Port="80,8080"') 1038 h = interact_2965(c, url) 1039 self.assertIn('$Port="80,8080"', h, 1040 "port with multiple values not returned with multiple " 1041 "values") 1042 1043 def test_no_return_comment(self): 1044 from cookielib import CookieJar, DefaultCookiePolicy 1045 1046 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 1047 url = "http://foo.bar.com/" 1048 interact_2965(c, url, 'spam=eggs; Version=1; ' 1049 'Comment="does anybody read these?"; ' 1050 'CommentURL="http://foo.bar.net/comment.html"') 1051 h = interact_2965(c, url) 1052 self.assertNotIn("Comment", h, 1053 "Comment or CommentURL cookie-attributes returned to server") 1054 1055 def test_Cookie_iterator(self): 1056 from cookielib import CookieJar, Cookie, DefaultCookiePolicy 1057 1058 cs = CookieJar(DefaultCookiePolicy(rfc2965=True)) 1059 # add some random cookies 1060 interact_2965(cs, "http://blah.spam.org/", 'foo=eggs; Version=1; ' 1061 'Comment="does anybody read these?"; ' 1062 'CommentURL="http://foo.bar.net/comment.html"') 1063 interact_netscape(cs, "http://www.acme.com/blah/", "spam=bar; secure") 1064 interact_2965(cs, "http://www.acme.com/blah/", 1065 "foo=bar; secure; Version=1") 1066 interact_2965(cs, "http://www.acme.com/blah/", 1067 "foo=bar; path=/; Version=1") 1068 interact_2965(cs, "http://www.sol.no", 1069 r'bang=wallop; version=1; domain=".sol.no"; ' 1070 r'port="90,100, 80,8080"; ' 1071 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "') 1072 1073 versions = [1, 1, 1, 0, 1] 1074 names = ["bang", "foo", "foo", "spam", "foo"] 1075 domains = [".sol.no", "blah.spam.org", "www.acme.com", 1076 "www.acme.com", "www.acme.com"] 1077 paths = ["/", "/", "/", "/blah", "/blah/"] 1078 1079 for i in range(4): 1080 i = 0 1081 for c in cs: 1082 self.assertIsInstance(c, Cookie) 1083 self.assertEqual(c.version, versions[i]) 1084 self.assertEqual(c.name, names[i]) 1085 self.assertEqual(c.domain, domains[i]) 1086 self.assertEqual(c.path, paths[i]) 1087 i = i + 1 1088 1089 def test_parse_ns_headers(self): 1090 from cookielib import parse_ns_headers 1091 1092 # missing domain value (invalid cookie) 1093 self.assertEqual( 1094 parse_ns_headers(["foo=bar; path=/; domain"]), 1095 [[("foo", "bar"), 1096 ("path", "/"), ("domain", None), ("version", "0")]] 1097 ) 1098 # invalid expires value 1099 self.assertEqual( 1100 parse_ns_headers(["foo=bar; expires=Foo Bar 12 33:22:11 2000"]), 1101 [[("foo", "bar"), ("expires", None), ("version", "0")]] 1102 ) 1103 # missing cookie value (valid cookie) 1104 self.assertEqual( 1105 parse_ns_headers(["foo"]), 1106 [[("foo", None), ("version", "0")]] 1107 ) 1108 # missing cookie values for parsed attributes 1109 self.assertEqual( 1110 parse_ns_headers(['foo=bar; expires']), 1111 [[('foo', 'bar'), ('expires', None), ('version', '0')]]) 1112 self.assertEqual( 1113 parse_ns_headers(['foo=bar; version']), 1114 [[('foo', 'bar'), ('version', None)]]) 1115 # shouldn't add version if header is empty 1116 self.assertEqual(parse_ns_headers([""]), []) 1117 1118 def test_bad_cookie_header(self): 1119 1120 def cookiejar_from_cookie_headers(headers): 1121 from cookielib import CookieJar 1122 from urllib2 import Request 1123 c = CookieJar() 1124 req = Request("http://www.example.com/") 1125 r = FakeResponse(headers, "http://www.example.com/") 1126 c.extract_cookies(r, req) 1127 return c 1128 1129 future = cookielib.time2netscape(time.time()+3600) 1130 1131 # none of these bad headers should cause an exception to be raised 1132 for headers in [ 1133 ["Set-Cookie: "], # actually, nothing wrong with this 1134 ["Set-Cookie2: "], # ditto 1135 # missing domain value 1136 ["Set-Cookie2: a=foo; path=/; Version=1; domain"], 1137 # bad max-age 1138 ["Set-Cookie: b=foo; max-age=oops"], 1139 # bad version 1140 ["Set-Cookie: b=foo; version=spam"], 1141 ["Set-Cookie:; Expires=%s" % future], 1142 ]: 1143 c = cookiejar_from_cookie_headers(headers) 1144 # these bad cookies shouldn't be set 1145 self.assertEqual(len(c), 0) 1146 1147 # cookie with invalid expires is treated as session cookie 1148 headers = ["Set-Cookie: c=foo; expires=Foo Bar 12 33:22:11 2000"] 1149 c = cookiejar_from_cookie_headers(headers) 1150 cookie = c._cookies["www.example.com"]["/"]["c"] 1151 self.assertIsNone(cookie.expires) 1152 1153 1154class LWPCookieTests(TestCase): 1155 # Tests taken from libwww-perl, with a few modifications and additions. 1156 1157 def test_netscape_example_1(self): 1158 from cookielib import CookieJar, DefaultCookiePolicy 1159 from urllib2 import Request 1160 1161 #------------------------------------------------------------------- 1162 # First we check that it works for the original example at 1163 # http://www.netscape.com/newsref/std/cookie_spec.html 1164 1165 # Client requests a document, and receives in the response: 1166 # 1167 # Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT 1168 # 1169 # When client requests a URL in path "/" on this server, it sends: 1170 # 1171 # Cookie: CUSTOMER=WILE_E_COYOTE 1172 # 1173 # Client requests a document, and receives in the response: 1174 # 1175 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/ 1176 # 1177 # When client requests a URL in path "/" on this server, it sends: 1178 # 1179 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001 1180 # 1181 # Client receives: 1182 # 1183 # Set-Cookie: SHIPPING=FEDEX; path=/fo 1184 # 1185 # When client requests a URL in path "/" on this server, it sends: 1186 # 1187 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001 1188 # 1189 # When client requests a URL in path "/foo" on this server, it sends: 1190 # 1191 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX 1192 # 1193 # The last Cookie is buggy, because both specifications say that the 1194 # most specific cookie must be sent first. SHIPPING=FEDEX is the 1195 # most specific and should thus be first. 1196 1197 year_plus_one = time.localtime()[0] + 1 1198 1199 headers = [] 1200 1201 c = CookieJar(DefaultCookiePolicy(rfc2965 = True)) 1202 1203 #req = Request("http://1.1.1.1/", 1204 # headers={"Host": "www.acme.com:80"}) 1205 req = Request("http://www.acme.com:80/", 1206 headers={"Host": "www.acme.com:80"}) 1207 1208 headers.append( 1209 "Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/ ; " 1210 "expires=Wednesday, 09-Nov-%d 23:12:40 GMT" % year_plus_one) 1211 res = FakeResponse(headers, "http://www.acme.com/") 1212 c.extract_cookies(res, req) 1213 1214 req = Request("http://www.acme.com/") 1215 c.add_cookie_header(req) 1216 1217 self.assertEqual(req.get_header("Cookie"), "CUSTOMER=WILE_E_COYOTE") 1218 self.assertEqual(req.get_header("Cookie2"), '$Version="1"') 1219 1220 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/") 1221 res = FakeResponse(headers, "http://www.acme.com/") 1222 c.extract_cookies(res, req) 1223 1224 req = Request("http://www.acme.com/foo/bar") 1225 c.add_cookie_header(req) 1226 1227 h = req.get_header("Cookie") 1228 self.assertIn("PART_NUMBER=ROCKET_LAUNCHER_0001", h) 1229 self.assertIn("CUSTOMER=WILE_E_COYOTE", h) 1230 1231 headers.append('Set-Cookie: SHIPPING=FEDEX; path=/foo') 1232 res = FakeResponse(headers, "http://www.acme.com") 1233 c.extract_cookies(res, req) 1234 1235 req = Request("http://www.acme.com/") 1236 c.add_cookie_header(req) 1237 1238 h = req.get_header("Cookie") 1239 self.assertIn("PART_NUMBER=ROCKET_LAUNCHER_0001", h) 1240 self.assertIn("CUSTOMER=WILE_E_COYOTE", h) 1241 self.assertNotIn("SHIPPING=FEDEX", h) 1242 1243 req = Request("http://www.acme.com/foo/") 1244 c.add_cookie_header(req) 1245 1246 h = req.get_header("Cookie") 1247 self.assertIn("PART_NUMBER=ROCKET_LAUNCHER_0001", h) 1248 self.assertIn("CUSTOMER=WILE_E_COYOTE", h) 1249 self.assertTrue(h.startswith("SHIPPING=FEDEX;")) 1250 1251 def test_netscape_example_2(self): 1252 from cookielib import CookieJar 1253 from urllib2 import Request 1254 1255 # Second Example transaction sequence: 1256 # 1257 # Assume all mappings from above have been cleared. 1258 # 1259 # Client receives: 1260 # 1261 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/ 1262 # 1263 # When client requests a URL in path "/" on this server, it sends: 1264 # 1265 # Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001 1266 # 1267 # Client receives: 1268 # 1269 # Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo 1270 # 1271 # When client requests a URL in path "/ammo" on this server, it sends: 1272 # 1273 # Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001 1274 # 1275 # NOTE: There are two name/value pairs named "PART_NUMBER" due to 1276 # the inheritance of the "/" mapping in addition to the "/ammo" mapping. 1277 1278 c = CookieJar() 1279 headers = [] 1280 1281 req = Request("http://www.acme.com/") 1282 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/") 1283 res = FakeResponse(headers, "http://www.acme.com/") 1284 1285 c.extract_cookies(res, req) 1286 1287 req = Request("http://www.acme.com/") 1288 c.add_cookie_header(req) 1289 1290 self.assertEqual(req.get_header("Cookie"), 1291 "PART_NUMBER=ROCKET_LAUNCHER_0001") 1292 1293 headers.append( 1294 "Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo") 1295 res = FakeResponse(headers, "http://www.acme.com/") 1296 c.extract_cookies(res, req) 1297 1298 req = Request("http://www.acme.com/ammo") 1299 c.add_cookie_header(req) 1300 1301 self.assertRegexpMatches(req.get_header("Cookie"), 1302 r"PART_NUMBER=RIDING_ROCKET_0023;\s*" 1303 "PART_NUMBER=ROCKET_LAUNCHER_0001") 1304 1305 def test_ietf_example_1(self): 1306 from cookielib import CookieJar, DefaultCookiePolicy 1307 #------------------------------------------------------------------- 1308 # Then we test with the examples from draft-ietf-http-state-man-mec-03.txt 1309 # 1310 # 5. EXAMPLES 1311 1312 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 1313 1314 # 1315 # 5.1 Example 1 1316 # 1317 # Most detail of request and response headers has been omitted. Assume 1318 # the user agent has no stored cookies. 1319 # 1320 # 1. User Agent -> Server 1321 # 1322 # POST /acme/login HTTP/1.1 1323 # [form data] 1324 # 1325 # User identifies self via a form. 1326 # 1327 # 2. Server -> User Agent 1328 # 1329 # HTTP/1.1 200 OK 1330 # Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme" 1331 # 1332 # Cookie reflects user's identity. 1333 1334 cookie = interact_2965( 1335 c, 'http://www.acme.com/acme/login', 1336 'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"') 1337 self.assertFalse(cookie) 1338 1339 # 1340 # 3. User Agent -> Server 1341 # 1342 # POST /acme/pickitem HTTP/1.1 1343 # Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme" 1344 # [form data] 1345 # 1346 # User selects an item for ``shopping basket.'' 1347 # 1348 # 4. Server -> User Agent 1349 # 1350 # HTTP/1.1 200 OK 1351 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1"; 1352 # Path="/acme" 1353 # 1354 # Shopping basket contains an item. 1355 1356 cookie = interact_2965(c, 'http://www.acme.com/acme/pickitem', 1357 'Part_Number="Rocket_Launcher_0001"; ' 1358 'Version="1"; Path="/acme"'); 1359 self.assertRegexpMatches(cookie, 1360 r'^\$Version="?1"?; Customer="?WILE_E_COYOTE"?; \$Path="/acme"$') 1361 1362 # 1363 # 5. User Agent -> Server 1364 # 1365 # POST /acme/shipping HTTP/1.1 1366 # Cookie: $Version="1"; 1367 # Customer="WILE_E_COYOTE"; $Path="/acme"; 1368 # Part_Number="Rocket_Launcher_0001"; $Path="/acme" 1369 # [form data] 1370 # 1371 # User selects shipping method from form. 1372 # 1373 # 6. Server -> User Agent 1374 # 1375 # HTTP/1.1 200 OK 1376 # Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme" 1377 # 1378 # New cookie reflects shipping method. 1379 1380 cookie = interact_2965(c, "http://www.acme.com/acme/shipping", 1381 'Shipping="FedEx"; Version="1"; Path="/acme"') 1382 1383 self.assertRegexpMatches(cookie, r'^\$Version="?1"?;') 1384 self.assertRegexpMatches(cookie, 1385 r'Part_Number="?Rocket_Launcher_0001"?;\s*\$Path="\/acme"') 1386 self.assertRegexpMatches(cookie, 1387 r'Customer="?WILE_E_COYOTE"?;\s*\$Path="\/acme"') 1388 1389 # 1390 # 7. User Agent -> Server 1391 # 1392 # POST /acme/process HTTP/1.1 1393 # Cookie: $Version="1"; 1394 # Customer="WILE_E_COYOTE"; $Path="/acme"; 1395 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"; 1396 # Shipping="FedEx"; $Path="/acme" 1397 # [form data] 1398 # 1399 # User chooses to process order. 1400 # 1401 # 8. Server -> User Agent 1402 # 1403 # HTTP/1.1 200 OK 1404 # 1405 # Transaction is complete. 1406 1407 cookie = interact_2965(c, "http://www.acme.com/acme/process") 1408 self.assertRegexpMatches(cookie, 1409 r'Shipping="?FedEx"?;\s*\$Path="\/acme"') 1410 self.assertIn("WILE_E_COYOTE", cookie) 1411 1412 # 1413 # The user agent makes a series of requests on the origin server, after 1414 # each of which it receives a new cookie. All the cookies have the same 1415 # Path attribute and (default) domain. Because the request URLs all have 1416 # /acme as a prefix, and that matches the Path attribute, each request 1417 # contains all the cookies received so far. 1418 1419 def test_ietf_example_2(self): 1420 from cookielib import CookieJar, DefaultCookiePolicy 1421 1422 # 5.2 Example 2 1423 # 1424 # This example illustrates the effect of the Path attribute. All detail 1425 # of request and response headers has been omitted. Assume the user agent 1426 # has no stored cookies. 1427 1428 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 1429 1430 # Imagine the user agent has received, in response to earlier requests, 1431 # the response headers 1432 # 1433 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1"; 1434 # Path="/acme" 1435 # 1436 # and 1437 # 1438 # Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1"; 1439 # Path="/acme/ammo" 1440 1441 interact_2965( 1442 c, "http://www.acme.com/acme/ammo/specific", 1443 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"', 1444 'Part_Number="Riding_Rocket_0023"; Version="1"; Path="/acme/ammo"') 1445 1446 # A subsequent request by the user agent to the (same) server for URLs of 1447 # the form /acme/ammo/... would include the following request header: 1448 # 1449 # Cookie: $Version="1"; 1450 # Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo"; 1451 # Part_Number="Rocket_Launcher_0001"; $Path="/acme" 1452 # 1453 # Note that the NAME=VALUE pair for the cookie with the more specific Path 1454 # attribute, /acme/ammo, comes before the one with the less specific Path 1455 # attribute, /acme. Further note that the same cookie name appears more 1456 # than once. 1457 1458 cookie = interact_2965(c, "http://www.acme.com/acme/ammo/...") 1459 self.assertRegexpMatches(cookie, 1460 r"Riding_Rocket_0023.*Rocket_Launcher_0001") 1461 1462 # A subsequent request by the user agent to the (same) server for a URL of 1463 # the form /acme/parts/ would include the following request header: 1464 # 1465 # Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme" 1466 # 1467 # Here, the second cookie's Path attribute /acme/ammo is not a prefix of 1468 # the request URL, /acme/parts/, so the cookie does not get forwarded to 1469 # the server. 1470 1471 cookie = interact_2965(c, "http://www.acme.com/acme/parts/") 1472 self.assertIn("Rocket_Launcher_0001", cookie) 1473 self.assertNotIn("Riding_Rocket_0023", cookie) 1474 1475 def test_rejection(self): 1476 # Test rejection of Set-Cookie2 responses based on domain, path, port. 1477 from cookielib import DefaultCookiePolicy, LWPCookieJar 1478 1479 pol = DefaultCookiePolicy(rfc2965=True) 1480 1481 c = LWPCookieJar(policy=pol) 1482 1483 max_age = "max-age=3600" 1484 1485 # illegal domain (no embedded dots) 1486 cookie = interact_2965(c, "http://www.acme.com", 1487 'foo=bar; domain=".com"; version=1') 1488 self.assertFalse(c) 1489 1490 # legal domain 1491 cookie = interact_2965(c, "http://www.acme.com", 1492 'ping=pong; domain="acme.com"; version=1') 1493 self.assertEqual(len(c), 1) 1494 1495 # illegal domain (host prefix "www.a" contains a dot) 1496 cookie = interact_2965(c, "http://www.a.acme.com", 1497 'whiz=bang; domain="acme.com"; version=1') 1498 self.assertEqual(len(c), 1) 1499 1500 # legal domain 1501 cookie = interact_2965(c, "http://www.a.acme.com", 1502 'wow=flutter; domain=".a.acme.com"; version=1') 1503 self.assertEqual(len(c), 2) 1504 1505 # can't partially match an IP-address 1506 cookie = interact_2965(c, "http://125.125.125.125", 1507 'zzzz=ping; domain="125.125.125"; version=1') 1508 self.assertEqual(len(c), 2) 1509 1510 # illegal path (must be prefix of request path) 1511 cookie = interact_2965(c, "http://www.sol.no", 1512 'blah=rhubarb; domain=".sol.no"; path="/foo"; ' 1513 'version=1') 1514 self.assertEqual(len(c), 2) 1515 1516 # legal path 1517 cookie = interact_2965(c, "http://www.sol.no/foo/bar", 1518 'bing=bong; domain=".sol.no"; path="/foo"; ' 1519 'version=1') 1520 self.assertEqual(len(c), 3) 1521 1522 # illegal port (request-port not in list) 1523 cookie = interact_2965(c, "http://www.sol.no", 1524 'whiz=ffft; domain=".sol.no"; port="90,100"; ' 1525 'version=1') 1526 self.assertEqual(len(c), 3) 1527 1528 # legal port 1529 cookie = interact_2965( 1530 c, "http://www.sol.no", 1531 r'bang=wallop; version=1; domain=".sol.no"; ' 1532 r'port="90,100, 80,8080"; ' 1533 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "') 1534 self.assertEqual(len(c), 4) 1535 1536 # port attribute without any value (current port) 1537 cookie = interact_2965(c, "http://www.sol.no", 1538 'foo9=bar; version=1; domain=".sol.no"; port; ' 1539 'max-age=100;') 1540 self.assertEqual(len(c), 5) 1541 1542 # encoded path 1543 # LWP has this test, but unescaping allowed path characters seems 1544 # like a bad idea, so I think this should fail: 1545## cookie = interact_2965(c, "http://www.sol.no/foo/", 1546## r'foo8=bar; version=1; path="/%66oo"') 1547 # but this is OK, because '<' is not an allowed HTTP URL path 1548 # character: 1549 cookie = interact_2965(c, "http://www.sol.no/<oo/", 1550 r'foo8=bar; version=1; path="/%3coo"') 1551 self.assertEqual(len(c), 6) 1552 1553 # save and restore 1554 filename = test_support.TESTFN 1555 1556 try: 1557 c.save(filename, ignore_discard=True) 1558 old = repr(c) 1559 1560 c = LWPCookieJar(policy=pol) 1561 c.load(filename, ignore_discard=True) 1562 finally: 1563 try: os.unlink(filename) 1564 except OSError: pass 1565 1566 self.assertEqual(old, repr(c)) 1567 1568 def test_url_encoding(self): 1569 # Try some URL encodings of the PATHs. 1570 # (the behaviour here has changed from libwww-perl) 1571 from cookielib import CookieJar, DefaultCookiePolicy 1572 1573 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 1574 interact_2965(c, "http://www.acme.com/foo%2f%25/%3c%3c%0Anew%E5/%E5", 1575 "foo = bar; version = 1") 1576 1577 cookie = interact_2965( 1578 c, "http://www.acme.com/foo%2f%25/<<%0anew�/���", 1579 'bar=baz; path="/foo/"; version=1'); 1580 version_re = re.compile(r'^\$version=\"?1\"?', re.I) 1581 self.assertIn("foo=bar", cookie) 1582 self.assertRegexpMatches(cookie, version_re) 1583 1584 cookie = interact_2965( 1585 c, "http://www.acme.com/foo/%25/<<%0anew�/���") 1586 self.assertFalse(cookie) 1587 1588 # unicode URL doesn't raise exception 1589 cookie = interact_2965(c, u"http://www.acme.com/\xfc") 1590 1591 def test_mozilla(self): 1592 # Save / load Mozilla/Netscape cookie file format. 1593 from cookielib import MozillaCookieJar, DefaultCookiePolicy 1594 1595 year_plus_one = time.localtime()[0] + 1 1596 1597 filename = test_support.TESTFN 1598 1599 c = MozillaCookieJar(filename, 1600 policy=DefaultCookiePolicy(rfc2965=True)) 1601 interact_2965(c, "http://www.acme.com/", 1602 "foo1=bar; max-age=100; Version=1") 1603 interact_2965(c, "http://www.acme.com/", 1604 'foo2=bar; port="80"; max-age=100; Discard; Version=1') 1605 interact_2965(c, "http://www.acme.com/", "foo3=bar; secure; Version=1") 1606 1607 expires = "expires=09-Nov-%d 23:12:40 GMT" % (year_plus_one,) 1608 interact_netscape(c, "http://www.foo.com/", 1609 "fooa=bar; %s" % expires) 1610 interact_netscape(c, "http://www.foo.com/", 1611 "foob=bar; Domain=.foo.com; %s" % expires) 1612 interact_netscape(c, "http://www.foo.com/", 1613 "fooc=bar; Domain=www.foo.com; %s" % expires) 1614 1615 def save_and_restore(cj, ignore_discard): 1616 try: 1617 cj.save(ignore_discard=ignore_discard) 1618 new_c = MozillaCookieJar(filename, 1619 DefaultCookiePolicy(rfc2965=True)) 1620 new_c.load(ignore_discard=ignore_discard) 1621 finally: 1622 try: os.unlink(filename) 1623 except OSError: pass 1624 return new_c 1625 1626 new_c = save_and_restore(c, True) 1627 self.assertEqual(len(new_c), 6) # none discarded 1628 self.assertIn("name='foo1', value='bar'", repr(new_c)) 1629 1630 new_c = save_and_restore(c, False) 1631 self.assertEqual(len(new_c), 4) # 2 of them discarded on save 1632 self.assertIn("name='foo1', value='bar'", repr(new_c)) 1633 1634 def test_netscape_misc(self): 1635 # Some additional Netscape cookies tests. 1636 from cookielib import CookieJar 1637 from urllib2 import Request 1638 1639 c = CookieJar() 1640 headers = [] 1641 req = Request("http://foo.bar.acme.com/foo") 1642 1643 # Netscape allows a host part that contains dots 1644 headers.append("Set-Cookie: Customer=WILE_E_COYOTE; domain=.acme.com") 1645 res = FakeResponse(headers, "http://www.acme.com/foo") 1646 c.extract_cookies(res, req) 1647 1648 # and that the domain is the same as the host without adding a leading 1649 # dot to the domain. Should not quote even if strange chars are used 1650 # in the cookie value. 1651 headers.append("Set-Cookie: PART_NUMBER=3,4; domain=foo.bar.acme.com") 1652 res = FakeResponse(headers, "http://www.acme.com/foo") 1653 c.extract_cookies(res, req) 1654 1655 req = Request("http://foo.bar.acme.com/foo") 1656 c.add_cookie_header(req) 1657 self.assertTrue( 1658 "PART_NUMBER=3,4" in req.get_header("Cookie") and 1659 "Customer=WILE_E_COYOTE" in req.get_header("Cookie")) 1660 1661 def test_intranet_domains_2965(self): 1662 # Test handling of local intranet hostnames without a dot. 1663 from cookielib import CookieJar, DefaultCookiePolicy 1664 1665 c = CookieJar(DefaultCookiePolicy(rfc2965=True)) 1666 interact_2965(c, "http://example/", 1667 "foo1=bar; PORT; Discard; Version=1;") 1668 cookie = interact_2965(c, "http://example/", 1669 'foo2=bar; domain=".local"; Version=1') 1670 self.assertIn("foo1=bar", cookie) 1671 1672 interact_2965(c, "http://example/", 'foo3=bar; Version=1') 1673 cookie = interact_2965(c, "http://example/") 1674 self.assertIn("foo2=bar", cookie) 1675 self.assertEqual(len(c), 3) 1676 1677 def test_intranet_domains_ns(self): 1678 from cookielib import CookieJar, DefaultCookiePolicy 1679 1680 c = CookieJar(DefaultCookiePolicy(rfc2965 = False)) 1681 interact_netscape(c, "http://example/", "foo1=bar") 1682 cookie = interact_netscape(c, "http://example/", 1683 'foo2=bar; domain=.local') 1684 self.assertEqual(len(c), 2) 1685 self.assertIn("foo1=bar", cookie) 1686 1687 cookie = interact_netscape(c, "http://example/") 1688 self.assertIn("foo2=bar", cookie) 1689 self.assertEqual(len(c), 2) 1690 1691 def test_empty_path(self): 1692 from cookielib import CookieJar, DefaultCookiePolicy 1693 from urllib2 import Request 1694 1695 # Test for empty path 1696 # Broken web-server ORION/1.3.38 returns to the client response like 1697 # 1698 # Set-Cookie: JSESSIONID=ABCDERANDOM123; Path= 1699 # 1700 # ie. with Path set to nothing. 1701 # In this case, extract_cookies() must set cookie to / (root) 1702 c = CookieJar(DefaultCookiePolicy(rfc2965 = True)) 1703 headers = [] 1704 1705 req = Request("http://www.ants.com/") 1706 headers.append("Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=") 1707 res = FakeResponse(headers, "http://www.ants.com/") 1708 c.extract_cookies(res, req) 1709 1710 req = Request("http://www.ants.com/") 1711 c.add_cookie_header(req) 1712 1713 self.assertEqual(req.get_header("Cookie"), 1714 "JSESSIONID=ABCDERANDOM123") 1715 self.assertEqual(req.get_header("Cookie2"), '$Version="1"') 1716 1717 # missing path in the request URI 1718 req = Request("http://www.ants.com:8080") 1719 c.add_cookie_header(req) 1720 1721 self.assertEqual(req.get_header("Cookie"), 1722 "JSESSIONID=ABCDERANDOM123") 1723 self.assertEqual(req.get_header("Cookie2"), '$Version="1"') 1724 1725 def test_session_cookies(self): 1726 from cookielib import CookieJar 1727 from urllib2 import Request 1728 1729 year_plus_one = time.localtime()[0] + 1 1730 1731 # Check session cookies are deleted properly by 1732 # CookieJar.clear_session_cookies method 1733 1734 req = Request('http://www.perlmeister.com/scripts') 1735 headers = [] 1736 headers.append("Set-Cookie: s1=session;Path=/scripts") 1737 headers.append("Set-Cookie: p1=perm; Domain=.perlmeister.com;" 1738 "Path=/;expires=Fri, 02-Feb-%d 23:24:20 GMT" % 1739 year_plus_one) 1740 headers.append("Set-Cookie: p2=perm;Path=/;expires=Fri, " 1741 "02-Feb-%d 23:24:20 GMT" % year_plus_one) 1742 headers.append("Set-Cookie: s2=session;Path=/scripts;" 1743 "Domain=.perlmeister.com") 1744 headers.append('Set-Cookie2: s3=session;Version=1;Discard;Path="/"') 1745 res = FakeResponse(headers, 'http://www.perlmeister.com/scripts') 1746 1747 c = CookieJar() 1748 c.extract_cookies(res, req) 1749 # How many session/permanent cookies do we have? 1750 counter = {"session_after": 0, 1751 "perm_after": 0, 1752 "session_before": 0, 1753 "perm_before": 0} 1754 for cookie in c: 1755 key = "%s_before" % cookie.value 1756 counter[key] = counter[key] + 1 1757 c.clear_session_cookies() 1758 # How many now? 1759 for cookie in c: 1760 key = "%s_after" % cookie.value 1761 counter[key] = counter[key] + 1 1762 1763 # a permanent cookie got lost accidentally 1764 self.assertEqual(counter["perm_after"], counter["perm_before"]) 1765 # a session cookie hasn't been cleared 1766 self.assertEqual(counter["session_after"], 0) 1767 # we didn't have session cookies in the first place 1768 self.assertNotEqual(counter["session_before"], 0) 1769 1770 1771def test_main(verbose=None): 1772 test_support.run_unittest( 1773 DateTimeTests, 1774 HeaderTests, 1775 CookieTests, 1776 FileCookieJarTests, 1777 LWPCookieTests, 1778 ) 1779 1780if __name__ == "__main__": 1781 test_main(verbose=True) 1782