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