home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 June / maximum-cd-2011-06.iso / DiscContents / LibO_3.3.1_Win_x86_install_multi.exe / libreoffice1.cab / test_cookielib.py < prev    next >
Encoding:
Python Source  |  2011-02-15  |  69.7 KB  |  1,737 lines

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