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