blob: 49e7d47b4ee3c612a1bcc9ecfe2b4f9bf21d0926 [file] [log] [blame]
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001# -*- coding: utf-8 -*-
2"""Tests for cookielib.py."""
3
4import re, os, time
5from unittest import TestCase
6
7from test import test_support
8
9class 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
101class HeaderTests(TestCase):
102 def test_parse_ns_headers(self):
103 from cookielib import parse_ns_headers
104
105 # quotes should be stripped
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000106 expected = [[('foo', 'bar'), ('expires', 2209069412L), ('version', '0')]]
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000107 for hdr in [
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000108 'foo=bar; expires=01 Jan 2040 22:23:32 GMT',
109 'foo=bar; expires="01 Jan 2040 22:23:32 GMT"',
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000110 ]:
111 self.assertEquals(parse_ns_headers([hdr]), expected)
112
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000113 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
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000123 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, """
162When parsing: '%s'
163Expected: '%s'
164Got: '%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, """
196When parsing: '%s'
197Expected: '%s'
198Got: '%s'
199Input was: '%s'
200""" % (arg, expect, res, input))
201
202
203class 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
214def interact_2965(cookiejar, url, *set_cookie_hdrs):
215 return _interact(cookiejar, url, set_cookie_hdrs, "Set-Cookie2")
216
217def interact_netscape(cookiejar, url, *set_cookie_hdrs):
218 return _interact(cookiejar, url, set_cookie_hdrs, "Set-Cookie")
219
220def _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
Martin v. Löwisc5574e82005-03-03 10:57:37 +0000234class 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
Neal Norwitz3e7de592005-12-23 21:24:35 +0000251 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
Martin v. Löwisc5574e82005-03-03 10:57:37 +0000276
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000277class 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
Neal Norwitz71dad722005-12-23 21:43:48 +0000389 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
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000422 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
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000459 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
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000472 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_two_component_domain_ns(self):
699 # Netscape: .www.bar.com, www.bar.com, .bar.com, bar.com, no domain
700 # should all get accepted, as should .acme.com, acme.com and no domain
701 # for 2-component domains like acme.com.
702 from cookielib import CookieJar, DefaultCookiePolicy
703
704 c = CookieJar()
705
706 # two-component V0 domain is OK
707 interact_netscape(c, "http://foo.net/", 'ns=bar')
708 self.assertEquals(len(c), 1)
709 self.assertEquals(c._cookies["foo.net"]["/"]["ns"].value, "bar")
710 self.assertEquals(interact_netscape(c, "http://foo.net/"), "ns=bar")
711 # *will* be returned to any other domain (unlike RFC 2965)...
712 self.assertEquals(interact_netscape(c, "http://www.foo.net/"),
713 "ns=bar")
714 # ...unless requested otherwise
715 pol = DefaultCookiePolicy(
716 strict_ns_domain=DefaultCookiePolicy.DomainStrictNonDomain)
717 c.set_policy(pol)
718 self.assertEquals(interact_netscape(c, "http://www.foo.net/"), "")
719
720 # unlike RFC 2965, even explicit two-component domain is OK,
721 # because .foo.net matches foo.net
722 interact_netscape(c, "http://foo.net/foo/",
723 'spam1=eggs; domain=foo.net')
724 # even if starts with a dot -- in NS rules, .foo.net matches foo.net!
725 interact_netscape(c, "http://foo.net/foo/bar/",
726 'spam2=eggs; domain=.foo.net')
727 self.assertEquals(len(c), 3)
728 self.assertEquals(c._cookies[".foo.net"]["/foo"]["spam1"].value,
729 "eggs")
730 self.assertEquals(c._cookies[".foo.net"]["/foo/bar"]["spam2"].value,
731 "eggs")
732 self.assertEquals(interact_netscape(c, "http://foo.net/foo/bar/"),
733 "spam2=eggs; spam1=eggs; ns=bar")
734
735 # top-level domain is too general
736 interact_netscape(c, "http://foo.net/", 'nini="ni"; domain=.net')
737 self.assertEquals(len(c), 3)
738
739## # Netscape protocol doesn't allow non-special top level domains (such
740## # as co.uk) in the domain attribute unless there are at least three
741## # dots in it.
742 # Oh yes it does! Real implementations don't check this, and real
743 # cookies (of course) rely on that behaviour.
744 interact_netscape(c, "http://foo.co.uk", 'nasty=trick; domain=.co.uk')
745## self.assertEquals(len(c), 2)
746 self.assertEquals(len(c), 4)
747
748 def test_two_component_domain_rfc2965(self):
749 from cookielib import CookieJar, DefaultCookiePolicy
750
751 pol = DefaultCookiePolicy(rfc2965=True)
752 c = CookieJar(pol)
753
754 # two-component V1 domain is OK
755 interact_2965(c, "http://foo.net/", 'foo=bar; Version="1"')
756 self.assertEquals(len(c), 1)
757 self.assertEquals(c._cookies["foo.net"]["/"]["foo"].value, "bar")
758 self.assertEquals(interact_2965(c, "http://foo.net/"),
759 "$Version=1; foo=bar")
760 # won't be returned to any other domain (because domain was implied)
761 self.assertEquals(interact_2965(c, "http://www.foo.net/"), "")
762
763 # unless domain is given explicitly, because then it must be
764 # rewritten to start with a dot: foo.net --> .foo.net, which does
765 # not domain-match foo.net
766 interact_2965(c, "http://foo.net/foo",
767 'spam=eggs; domain=foo.net; path=/foo; Version="1"')
768 self.assertEquals(len(c), 1)
769 self.assertEquals(interact_2965(c, "http://foo.net/foo"),
770 "$Version=1; foo=bar")
771
772 # explicit foo.net from three-component domain www.foo.net *does* get
773 # set, because .foo.net domain-matches .foo.net
774 interact_2965(c, "http://www.foo.net/foo/",
775 'spam=eggs; domain=foo.net; Version="1"')
776 self.assertEquals(c._cookies[".foo.net"]["/foo/"]["spam"].value,
777 "eggs")
778 self.assertEquals(len(c), 2)
779 self.assertEquals(interact_2965(c, "http://foo.net/foo/"),
780 "$Version=1; foo=bar")
781 self.assertEquals(interact_2965(c, "http://www.foo.net/foo/"),
782 '$Version=1; spam=eggs; $Domain="foo.net"')
783
784 # top-level domain is too general
785 interact_2965(c, "http://foo.net/",
786 'ni="ni"; domain=".net"; Version="1"')
787 self.assertEquals(len(c), 2)
788
789 # RFC 2965 doesn't require blocking this
790 interact_2965(c, "http://foo.co.uk/",
791 'nasty=trick; domain=.co.uk; Version="1"')
792 self.assertEquals(len(c), 3)
793
794 def test_domain_allow(self):
795 from cookielib import CookieJar, DefaultCookiePolicy
796 from urllib2 import Request
797
798 c = CookieJar(policy=DefaultCookiePolicy(
799 blocked_domains=["acme.com"],
800 allowed_domains=["www.acme.com"]))
801
802 req = Request("http://acme.com/")
803 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
804 res = FakeResponse(headers, "http://acme.com/")
805 c.extract_cookies(res, req)
806 self.assertEquals(len(c), 0)
807
808 req = Request("http://www.acme.com/")
809 res = FakeResponse(headers, "http://www.acme.com/")
810 c.extract_cookies(res, req)
811 self.assertEquals(len(c), 1)
812
813 req = Request("http://www.coyote.com/")
814 res = FakeResponse(headers, "http://www.coyote.com/")
815 c.extract_cookies(res, req)
816 self.assertEquals(len(c), 1)
817
818 # set a cookie with non-allowed domain...
819 req = Request("http://www.coyote.com/")
820 res = FakeResponse(headers, "http://www.coyote.com/")
821 cookies = c.make_cookies(res, req)
822 c.set_cookie(cookies[0])
823 self.assertEquals(len(c), 2)
824 # ... and check is doesn't get returned
825 c.add_cookie_header(req)
826 self.assert_(not req.has_header("Cookie"))
827
828 def test_domain_block(self):
829 from cookielib import CookieJar, DefaultCookiePolicy
830 from urllib2 import Request
831
832 pol = DefaultCookiePolicy(
833 rfc2965=True, blocked_domains=[".acme.com"])
834 c = CookieJar(policy=pol)
835 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
836
837 req = Request("http://www.acme.com/")
838 res = FakeResponse(headers, "http://www.acme.com/")
839 c.extract_cookies(res, req)
840 self.assertEquals(len(c), 0)
841
842 p = pol.set_blocked_domains(["acme.com"])
843 c.extract_cookies(res, req)
844 self.assertEquals(len(c), 1)
845
846 c.clear()
847 req = Request("http://www.roadrunner.net/")
848 res = FakeResponse(headers, "http://www.roadrunner.net/")
849 c.extract_cookies(res, req)
850 self.assertEquals(len(c), 1)
851 req = Request("http://www.roadrunner.net/")
852 c.add_cookie_header(req)
853 self.assert_((req.has_header("Cookie") and
854 req.has_header("Cookie2")))
855
856 c.clear()
857 pol.set_blocked_domains([".acme.com"])
858 c.extract_cookies(res, req)
859 self.assertEquals(len(c), 1)
860
861 # set a cookie with blocked domain...
862 req = Request("http://www.acme.com/")
863 res = FakeResponse(headers, "http://www.acme.com/")
864 cookies = c.make_cookies(res, req)
865 c.set_cookie(cookies[0])
866 self.assertEquals(len(c), 2)
867 # ... and check is doesn't get returned
868 c.add_cookie_header(req)
869 self.assert_(not req.has_header("Cookie"))
870
871 def test_secure(self):
872 from cookielib import CookieJar, DefaultCookiePolicy
873
874 for ns in True, False:
875 for whitespace in " ", "":
876 c = CookieJar()
877 if ns:
878 pol = DefaultCookiePolicy(rfc2965=False)
879 int = interact_netscape
880 vs = ""
881 else:
882 pol = DefaultCookiePolicy(rfc2965=True)
883 int = interact_2965
884 vs = "; Version=1"
885 c.set_policy(pol)
886 url = "http://www.acme.com/"
887 int(c, url, "foo1=bar%s%s" % (vs, whitespace))
888 int(c, url, "foo2=bar%s; secure%s" % (vs, whitespace))
889 self.assert_(
890 not c._cookies["www.acme.com"]["/"]["foo1"].secure,
891 "non-secure cookie registered secure")
892 self.assert_(
893 c._cookies["www.acme.com"]["/"]["foo2"].secure,
894 "secure cookie registered non-secure")
895
896 def test_quote_cookie_value(self):
897 from cookielib import CookieJar, DefaultCookiePolicy
898 c = CookieJar(policy=DefaultCookiePolicy(rfc2965=True))
899 interact_2965(c, "http://www.acme.com/", r'foo=\b"a"r; Version=1')
900 h = interact_2965(c, "http://www.acme.com/")
901 self.assertEquals(h, r'$Version=1; foo=\\b\"a\"r')
902
903 def test_missing_final_slash(self):
904 # Missing slash from request URL's abs_path should be assumed present.
905 from cookielib import CookieJar, DefaultCookiePolicy
906 from urllib2 import Request
907 url = "http://www.acme.com"
908 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
909 interact_2965(c, url, "foo=bar; Version=1")
910 req = Request(url)
911 self.assertEquals(len(c), 1)
912 c.add_cookie_header(req)
913 self.assert_(req.has_header("Cookie"))
914
915 def test_domain_mirror(self):
916 from cookielib import CookieJar, DefaultCookiePolicy
917
918 pol = DefaultCookiePolicy(rfc2965=True)
919
920 c = CookieJar(pol)
921 url = "http://foo.bar.com/"
922 interact_2965(c, url, "spam=eggs; Version=1")
923 h = interact_2965(c, url)
924 self.assert_("Domain" not in h,
925 "absent domain returned with domain present")
926
927 c = CookieJar(pol)
928 url = "http://foo.bar.com/"
929 interact_2965(c, url, 'spam=eggs; Version=1; Domain=.bar.com')
930 h = interact_2965(c, url)
931 self.assert_('$Domain=".bar.com"' in h, "domain not returned")
932
933 c = CookieJar(pol)
934 url = "http://foo.bar.com/"
935 # note missing initial dot in Domain
936 interact_2965(c, url, 'spam=eggs; Version=1; Domain=bar.com')
937 h = interact_2965(c, url)
938 self.assert_('$Domain="bar.com"' in h, "domain not returned")
939
940 def test_path_mirror(self):
941 from cookielib import CookieJar, DefaultCookiePolicy
942
943 pol = DefaultCookiePolicy(rfc2965=True)
944
945 c = CookieJar(pol)
946 url = "http://foo.bar.com/"
947 interact_2965(c, url, "spam=eggs; Version=1")
948 h = interact_2965(c, url)
949 self.assert_("Path" not in h,
950 "absent path returned with path present")
951
952 c = CookieJar(pol)
953 url = "http://foo.bar.com/"
954 interact_2965(c, url, 'spam=eggs; Version=1; Path=/')
955 h = interact_2965(c, url)
956 self.assert_('$Path="/"' in h, "path not returned")
957
958 def test_port_mirror(self):
959 from cookielib import CookieJar, DefaultCookiePolicy
960
961 pol = DefaultCookiePolicy(rfc2965=True)
962
963 c = CookieJar(pol)
964 url = "http://foo.bar.com/"
965 interact_2965(c, url, "spam=eggs; Version=1")
966 h = interact_2965(c, url)
967 self.assert_("Port" not in h,
968 "absent port returned with port present")
969
970 c = CookieJar(pol)
971 url = "http://foo.bar.com/"
972 interact_2965(c, url, "spam=eggs; Version=1; Port")
973 h = interact_2965(c, url)
974 self.assert_(re.search("\$Port([^=]|$)", h),
975 "port with no value not returned with no value")
976
977 c = CookieJar(pol)
978 url = "http://foo.bar.com/"
979 interact_2965(c, url, 'spam=eggs; Version=1; Port="80"')
980 h = interact_2965(c, url)
981 self.assert_('$Port="80"' in h,
982 "port with single value not returned with single value")
983
984 c = CookieJar(pol)
985 url = "http://foo.bar.com/"
986 interact_2965(c, url, 'spam=eggs; Version=1; Port="80,8080"')
987 h = interact_2965(c, url)
988 self.assert_('$Port="80,8080"' in h,
989 "port with multiple values not returned with multiple "
990 "values")
991
992 def test_no_return_comment(self):
993 from cookielib import CookieJar, DefaultCookiePolicy
994
995 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
996 url = "http://foo.bar.com/"
997 interact_2965(c, url, 'spam=eggs; Version=1; '
998 'Comment="does anybody read these?"; '
999 'CommentURL="http://foo.bar.net/comment.html"')
1000 h = interact_2965(c, url)
1001 self.assert_(
1002 "Comment" not in h,
1003 "Comment or CommentURL cookie-attributes returned to server")
1004
1005 def test_Cookie_iterator(self):
1006 from cookielib import CookieJar, Cookie, DefaultCookiePolicy
1007
1008 cs = CookieJar(DefaultCookiePolicy(rfc2965=True))
1009 # add some random cookies
1010 interact_2965(cs, "http://blah.spam.org/", 'foo=eggs; Version=1; '
1011 'Comment="does anybody read these?"; '
1012 'CommentURL="http://foo.bar.net/comment.html"')
1013 interact_netscape(cs, "http://www.acme.com/blah/", "spam=bar; secure")
1014 interact_2965(cs, "http://www.acme.com/blah/",
1015 "foo=bar; secure; Version=1")
1016 interact_2965(cs, "http://www.acme.com/blah/",
1017 "foo=bar; path=/; Version=1")
1018 interact_2965(cs, "http://www.sol.no",
1019 r'bang=wallop; version=1; domain=".sol.no"; '
1020 r'port="90,100, 80,8080"; '
1021 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "')
1022
1023 versions = [1, 1, 1, 0, 1]
1024 names = ["bang", "foo", "foo", "spam", "foo"]
1025 domains = [".sol.no", "blah.spam.org", "www.acme.com",
1026 "www.acme.com", "www.acme.com"]
1027 paths = ["/", "/", "/", "/blah", "/blah/"]
1028
1029 for i in range(4):
1030 i = 0
1031 for c in cs:
1032 self.assert_(isinstance(c, Cookie))
1033 self.assertEquals(c.version, versions[i])
1034 self.assertEquals(c.name, names[i])
1035 self.assertEquals(c.domain, domains[i])
1036 self.assertEquals(c.path, paths[i])
1037 i = i + 1
1038
1039 def test_parse_ns_headers(self):
1040 from cookielib import parse_ns_headers
1041
1042 # missing domain value (invalid cookie)
1043 self.assertEquals(
1044 parse_ns_headers(["foo=bar; path=/; domain"]),
1045 [[("foo", "bar"),
1046 ("path", "/"), ("domain", None), ("version", "0")]]
1047 )
1048 # invalid expires value
1049 self.assertEquals(
1050 parse_ns_headers(["foo=bar; expires=Foo Bar 12 33:22:11 2000"]),
1051 [[("foo", "bar"), ("expires", None), ("version", "0")]]
1052 )
1053 # missing cookie value (valid cookie)
1054 self.assertEquals(
1055 parse_ns_headers(["foo"]),
1056 [[("foo", None), ("version", "0")]]
1057 )
1058 # shouldn't add version if header is empty
1059 self.assertEquals(parse_ns_headers([""]), [])
1060
1061 def test_bad_cookie_header(self):
1062
1063 def cookiejar_from_cookie_headers(headers):
1064 from cookielib import CookieJar
1065 from urllib2 import Request
1066 c = CookieJar()
1067 req = Request("http://www.example.com/")
1068 r = FakeResponse(headers, "http://www.example.com/")
1069 c.extract_cookies(r, req)
1070 return c
1071
1072 # none of these bad headers should cause an exception to be raised
1073 for headers in [
1074 ["Set-Cookie: "], # actually, nothing wrong with this
1075 ["Set-Cookie2: "], # ditto
1076 # missing domain value
1077 ["Set-Cookie2: a=foo; path=/; Version=1; domain"],
1078 # bad max-age
1079 ["Set-Cookie: b=foo; max-age=oops"],
1080 ]:
1081 c = cookiejar_from_cookie_headers(headers)
1082 # these bad cookies shouldn't be set
1083 self.assertEquals(len(c), 0)
1084
1085 # cookie with invalid expires is treated as session cookie
1086 headers = ["Set-Cookie: c=foo; expires=Foo Bar 12 33:22:11 2000"]
1087 c = cookiejar_from_cookie_headers(headers)
1088 cookie = c._cookies["www.example.com"]["/"]["c"]
1089 self.assert_(cookie.expires is None)
1090
1091
1092class LWPCookieTests(TestCase):
1093 # Tests taken from libwww-perl, with a few modifications and additions.
1094
1095 def test_netscape_example_1(self):
1096 from cookielib import CookieJar, DefaultCookiePolicy
1097 from urllib2 import Request
1098
1099 #-------------------------------------------------------------------
1100 # First we check that it works for the original example at
1101 # http://www.netscape.com/newsref/std/cookie_spec.html
1102
1103 # Client requests a document, and receives in the response:
1104 #
1105 # Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
1106 #
1107 # When client requests a URL in path "/" on this server, it sends:
1108 #
1109 # Cookie: CUSTOMER=WILE_E_COYOTE
1110 #
1111 # Client requests a document, and receives in the response:
1112 #
1113 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
1114 #
1115 # When client requests a URL in path "/" on this server, it sends:
1116 #
1117 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
1118 #
1119 # Client receives:
1120 #
1121 # Set-Cookie: SHIPPING=FEDEX; path=/fo
1122 #
1123 # When client requests a URL in path "/" on this server, it sends:
1124 #
1125 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
1126 #
1127 # When client requests a URL in path "/foo" on this server, it sends:
1128 #
1129 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX
1130 #
1131 # The last Cookie is buggy, because both specifications say that the
1132 # most specific cookie must be sent first. SHIPPING=FEDEX is the
1133 # most specific and should thus be first.
1134
1135 year_plus_one = time.localtime()[0] + 1
1136
1137 headers = []
1138
1139 c = CookieJar(DefaultCookiePolicy(rfc2965 = True))
1140
1141 #req = Request("http://1.1.1.1/",
1142 # headers={"Host": "www.acme.com:80"})
1143 req = Request("http://www.acme.com:80/",
1144 headers={"Host": "www.acme.com:80"})
1145
1146 headers.append(
1147 "Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/ ; "
1148 "expires=Wednesday, 09-Nov-%d 23:12:40 GMT" % year_plus_one)
1149 res = FakeResponse(headers, "http://www.acme.com/")
1150 c.extract_cookies(res, req)
1151
1152 req = Request("http://www.acme.com/")
1153 c.add_cookie_header(req)
1154
1155 self.assertEqual(req.get_header("Cookie"), "CUSTOMER=WILE_E_COYOTE")
1156 self.assertEqual(req.get_header("Cookie2"), '$Version="1"')
1157
1158 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/")
1159 res = FakeResponse(headers, "http://www.acme.com/")
1160 c.extract_cookies(res, req)
1161
1162 req = Request("http://www.acme.com/foo/bar")
1163 c.add_cookie_header(req)
1164
1165 h = req.get_header("Cookie")
1166 self.assert_("PART_NUMBER=ROCKET_LAUNCHER_0001" in h and
1167 "CUSTOMER=WILE_E_COYOTE" in h)
1168
1169 headers.append('Set-Cookie: SHIPPING=FEDEX; path=/foo')
1170 res = FakeResponse(headers, "http://www.acme.com")
1171 c.extract_cookies(res, req)
1172
1173 req = Request("http://www.acme.com/")
1174 c.add_cookie_header(req)
1175
1176 h = req.get_header("Cookie")
1177 self.assert_("PART_NUMBER=ROCKET_LAUNCHER_0001" in h and
1178 "CUSTOMER=WILE_E_COYOTE" in h and
1179 "SHIPPING=FEDEX" not in h)
1180
1181 req = Request("http://www.acme.com/foo/")
1182 c.add_cookie_header(req)
1183
1184 h = req.get_header("Cookie")
1185 self.assert_(("PART_NUMBER=ROCKET_LAUNCHER_0001" in h and
1186 "CUSTOMER=WILE_E_COYOTE" in h and
1187 h.startswith("SHIPPING=FEDEX;")))
1188
1189 def test_netscape_example_2(self):
1190 from cookielib import CookieJar
1191 from urllib2 import Request
1192
1193 # Second Example transaction sequence:
1194 #
1195 # Assume all mappings from above have been cleared.
1196 #
1197 # Client receives:
1198 #
1199 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
1200 #
1201 # When client requests a URL in path "/" on this server, it sends:
1202 #
1203 # Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
1204 #
1205 # Client receives:
1206 #
1207 # Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
1208 #
1209 # When client requests a URL in path "/ammo" on this server, it sends:
1210 #
1211 # Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
1212 #
1213 # NOTE: There are two name/value pairs named "PART_NUMBER" due to
1214 # the inheritance of the "/" mapping in addition to the "/ammo" mapping.
1215
1216 c = CookieJar()
1217 headers = []
1218
1219 req = Request("http://www.acme.com/")
1220 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/")
1221 res = FakeResponse(headers, "http://www.acme.com/")
1222
1223 c.extract_cookies(res, req)
1224
1225 req = Request("http://www.acme.com/")
1226 c.add_cookie_header(req)
1227
1228 self.assertEquals(req.get_header("Cookie"),
1229 "PART_NUMBER=ROCKET_LAUNCHER_0001")
1230
1231 headers.append(
1232 "Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo")
1233 res = FakeResponse(headers, "http://www.acme.com/")
1234 c.extract_cookies(res, req)
1235
1236 req = Request("http://www.acme.com/ammo")
1237 c.add_cookie_header(req)
1238
1239 self.assert_(re.search(r"PART_NUMBER=RIDING_ROCKET_0023;\s*"
1240 "PART_NUMBER=ROCKET_LAUNCHER_0001",
1241 req.get_header("Cookie")))
1242
1243 def test_ietf_example_1(self):
1244 from cookielib import CookieJar, DefaultCookiePolicy
1245 #-------------------------------------------------------------------
1246 # Then we test with the examples from draft-ietf-http-state-man-mec-03.txt
1247 #
1248 # 5. EXAMPLES
1249
1250 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1251
1252 #
1253 # 5.1 Example 1
1254 #
1255 # Most detail of request and response headers has been omitted. Assume
1256 # the user agent has no stored cookies.
1257 #
1258 # 1. User Agent -> Server
1259 #
1260 # POST /acme/login HTTP/1.1
1261 # [form data]
1262 #
1263 # User identifies self via a form.
1264 #
1265 # 2. Server -> User Agent
1266 #
1267 # HTTP/1.1 200 OK
1268 # Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
1269 #
1270 # Cookie reflects user's identity.
1271
1272 cookie = interact_2965(
1273 c, 'http://www.acme.com/acme/login',
1274 'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"')
1275 self.assert_(not cookie)
1276
1277 #
1278 # 3. User Agent -> Server
1279 #
1280 # POST /acme/pickitem HTTP/1.1
1281 # Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
1282 # [form data]
1283 #
1284 # User selects an item for ``shopping basket.''
1285 #
1286 # 4. Server -> User Agent
1287 #
1288 # HTTP/1.1 200 OK
1289 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
1290 # Path="/acme"
1291 #
1292 # Shopping basket contains an item.
1293
1294 cookie = interact_2965(c, 'http://www.acme.com/acme/pickitem',
1295 'Part_Number="Rocket_Launcher_0001"; '
1296 'Version="1"; Path="/acme"');
1297 self.assert_(re.search(
1298 r'^\$Version="?1"?; Customer="?WILE_E_COYOTE"?; \$Path="/acme"$',
1299 cookie))
1300
1301 #
1302 # 5. User Agent -> Server
1303 #
1304 # POST /acme/shipping HTTP/1.1
1305 # Cookie: $Version="1";
1306 # Customer="WILE_E_COYOTE"; $Path="/acme";
1307 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1308 # [form data]
1309 #
1310 # User selects shipping method from form.
1311 #
1312 # 6. Server -> User Agent
1313 #
1314 # HTTP/1.1 200 OK
1315 # Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"
1316 #
1317 # New cookie reflects shipping method.
1318
1319 cookie = interact_2965(c, "http://www.acme.com/acme/shipping",
1320 'Shipping="FedEx"; Version="1"; Path="/acme"')
1321
1322 self.assert_(re.search(r'^\$Version="?1"?;', cookie))
1323 self.assert_(re.search(r'Part_Number="?Rocket_Launcher_0001"?;'
1324 '\s*\$Path="\/acme"', cookie))
1325 self.assert_(re.search(r'Customer="?WILE_E_COYOTE"?;\s*\$Path="\/acme"',
1326 cookie))
1327
1328 #
1329 # 7. User Agent -> Server
1330 #
1331 # POST /acme/process HTTP/1.1
1332 # Cookie: $Version="1";
1333 # Customer="WILE_E_COYOTE"; $Path="/acme";
1334 # Part_Number="Rocket_Launcher_0001"; $Path="/acme";
1335 # Shipping="FedEx"; $Path="/acme"
1336 # [form data]
1337 #
1338 # User chooses to process order.
1339 #
1340 # 8. Server -> User Agent
1341 #
1342 # HTTP/1.1 200 OK
1343 #
1344 # Transaction is complete.
1345
1346 cookie = interact_2965(c, "http://www.acme.com/acme/process")
1347 self.assert_(
1348 re.search(r'Shipping="?FedEx"?;\s*\$Path="\/acme"', cookie) and
1349 "WILE_E_COYOTE" in cookie)
1350
1351 #
1352 # The user agent makes a series of requests on the origin server, after
1353 # each of which it receives a new cookie. All the cookies have the same
1354 # Path attribute and (default) domain. Because the request URLs all have
1355 # /acme as a prefix, and that matches the Path attribute, each request
1356 # contains all the cookies received so far.
1357
1358 def test_ietf_example_2(self):
1359 from cookielib import CookieJar, DefaultCookiePolicy
1360
1361 # 5.2 Example 2
1362 #
1363 # This example illustrates the effect of the Path attribute. All detail
1364 # of request and response headers has been omitted. Assume the user agent
1365 # has no stored cookies.
1366
1367 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1368
1369 # Imagine the user agent has received, in response to earlier requests,
1370 # the response headers
1371 #
1372 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
1373 # Path="/acme"
1374 #
1375 # and
1376 #
1377 # Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1";
1378 # Path="/acme/ammo"
1379
1380 interact_2965(
1381 c, "http://www.acme.com/acme/ammo/specific",
1382 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"',
1383 'Part_Number="Riding_Rocket_0023"; Version="1"; Path="/acme/ammo"')
1384
1385 # A subsequent request by the user agent to the (same) server for URLs of
1386 # the form /acme/ammo/... would include the following request header:
1387 #
1388 # Cookie: $Version="1";
1389 # Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
1390 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1391 #
1392 # Note that the NAME=VALUE pair for the cookie with the more specific Path
1393 # attribute, /acme/ammo, comes before the one with the less specific Path
1394 # attribute, /acme. Further note that the same cookie name appears more
1395 # than once.
1396
1397 cookie = interact_2965(c, "http://www.acme.com/acme/ammo/...")
1398 self.assert_(
1399 re.search(r"Riding_Rocket_0023.*Rocket_Launcher_0001", cookie))
1400
1401 # A subsequent request by the user agent to the (same) server for a URL of
1402 # the form /acme/parts/ would include the following request header:
1403 #
1404 # Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1405 #
1406 # Here, the second cookie's Path attribute /acme/ammo is not a prefix of
1407 # the request URL, /acme/parts/, so the cookie does not get forwarded to
1408 # the server.
1409
1410 cookie = interact_2965(c, "http://www.acme.com/acme/parts/")
1411 self.assert_("Rocket_Launcher_0001" in cookie and
1412 "Riding_Rocket_0023" not in cookie)
1413
1414 def test_rejection(self):
1415 # Test rejection of Set-Cookie2 responses based on domain, path, port.
1416 from cookielib import DefaultCookiePolicy, LWPCookieJar
1417
1418 pol = DefaultCookiePolicy(rfc2965=True)
1419
1420 c = LWPCookieJar(policy=pol)
1421
1422 max_age = "max-age=3600"
1423
1424 # illegal domain (no embedded dots)
1425 cookie = interact_2965(c, "http://www.acme.com",
1426 'foo=bar; domain=".com"; version=1')
1427 self.assert_(not c)
1428
1429 # legal domain
1430 cookie = interact_2965(c, "http://www.acme.com",
1431 'ping=pong; domain="acme.com"; version=1')
1432 self.assertEquals(len(c), 1)
1433
1434 # illegal domain (host prefix "www.a" contains a dot)
1435 cookie = interact_2965(c, "http://www.a.acme.com",
1436 'whiz=bang; domain="acme.com"; version=1')
1437 self.assertEquals(len(c), 1)
1438
1439 # legal domain
1440 cookie = interact_2965(c, "http://www.a.acme.com",
1441 'wow=flutter; domain=".a.acme.com"; version=1')
1442 self.assertEquals(len(c), 2)
1443
1444 # can't partially match an IP-address
1445 cookie = interact_2965(c, "http://125.125.125.125",
1446 'zzzz=ping; domain="125.125.125"; version=1')
1447 self.assertEquals(len(c), 2)
1448
1449 # illegal path (must be prefix of request path)
1450 cookie = interact_2965(c, "http://www.sol.no",
1451 'blah=rhubarb; domain=".sol.no"; path="/foo"; '
1452 'version=1')
1453 self.assertEquals(len(c), 2)
1454
1455 # legal path
1456 cookie = interact_2965(c, "http://www.sol.no/foo/bar",
1457 'bing=bong; domain=".sol.no"; path="/foo"; '
1458 'version=1')
1459 self.assertEquals(len(c), 3)
1460
1461 # illegal port (request-port not in list)
1462 cookie = interact_2965(c, "http://www.sol.no",
1463 'whiz=ffft; domain=".sol.no"; port="90,100"; '
1464 'version=1')
1465 self.assertEquals(len(c), 3)
1466
1467 # legal port
1468 cookie = interact_2965(
1469 c, "http://www.sol.no",
1470 r'bang=wallop; version=1; domain=".sol.no"; '
1471 r'port="90,100, 80,8080"; '
1472 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "')
1473 self.assertEquals(len(c), 4)
1474
1475 # port attribute without any value (current port)
1476 cookie = interact_2965(c, "http://www.sol.no",
1477 'foo9=bar; version=1; domain=".sol.no"; port; '
1478 'max-age=100;')
1479 self.assertEquals(len(c), 5)
1480
1481 # encoded path
1482 # LWP has this test, but unescaping allowed path characters seems
1483 # like a bad idea, so I think this should fail:
1484## cookie = interact_2965(c, "http://www.sol.no/foo/",
1485## r'foo8=bar; version=1; path="/%66oo"')
1486 # but this is OK, because '<' is not an allowed HTTP URL path
1487 # character:
1488 cookie = interact_2965(c, "http://www.sol.no/<oo/",
1489 r'foo8=bar; version=1; path="/%3coo"')
1490 self.assertEquals(len(c), 6)
1491
1492 # save and restore
1493 filename = test_support.TESTFN
1494
1495 try:
1496 c.save(filename, ignore_discard=True)
1497 old = repr(c)
1498
1499 c = LWPCookieJar(policy=pol)
1500 c.load(filename, ignore_discard=True)
1501 finally:
1502 try: os.unlink(filename)
1503 except OSError: pass
1504
1505 self.assertEquals(old, repr(c))
1506
1507 def test_url_encoding(self):
1508 # Try some URL encodings of the PATHs.
1509 # (the behaviour here has changed from libwww-perl)
1510 from cookielib import CookieJar, DefaultCookiePolicy
1511
1512 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1513 interact_2965(c, "http://www.acme.com/foo%2f%25/%3c%3c%0Anew%E5/%E5",
1514 "foo = bar; version = 1")
1515
1516 cookie = interact_2965(
1517 c, "http://www.acme.com/foo%2f%25/<<%0anewå/æøå",
1518 'bar=baz; path="/foo/"; version=1');
1519 version_re = re.compile(r'^\$version=\"?1\"?', re.I)
1520 self.assert_("foo=bar" in cookie and version_re.search(cookie))
1521
1522 cookie = interact_2965(
1523 c, "http://www.acme.com/foo/%25/<<%0anewå/æøå")
1524 self.assert_(not cookie)
1525
1526 # unicode URL doesn't raise exception
1527 cookie = interact_2965(c, u"http://www.acme.com/\xfc")
1528
1529 def test_mozilla(self):
1530 # Save / load Mozilla/Netscape cookie file format.
1531 from cookielib import MozillaCookieJar, DefaultCookiePolicy
1532
1533 year_plus_one = time.localtime()[0] + 1
1534
1535 filename = test_support.TESTFN
1536
1537 c = MozillaCookieJar(filename,
1538 policy=DefaultCookiePolicy(rfc2965=True))
1539 interact_2965(c, "http://www.acme.com/",
1540 "foo1=bar; max-age=100; Version=1")
1541 interact_2965(c, "http://www.acme.com/",
1542 'foo2=bar; port="80"; max-age=100; Discard; Version=1')
1543 interact_2965(c, "http://www.acme.com/", "foo3=bar; secure; Version=1")
1544
1545 expires = "expires=09-Nov-%d 23:12:40 GMT" % (year_plus_one,)
1546 interact_netscape(c, "http://www.foo.com/",
1547 "fooa=bar; %s" % expires)
1548 interact_netscape(c, "http://www.foo.com/",
1549 "foob=bar; Domain=.foo.com; %s" % expires)
1550 interact_netscape(c, "http://www.foo.com/",
1551 "fooc=bar; Domain=www.foo.com; %s" % expires)
1552
1553 def save_and_restore(cj, ignore_discard):
1554 try:
1555 cj.save(ignore_discard=ignore_discard)
1556 new_c = MozillaCookieJar(filename,
1557 DefaultCookiePolicy(rfc2965=True))
1558 new_c.load(ignore_discard=ignore_discard)
1559 finally:
1560 try: os.unlink(filename)
1561 except OSError: pass
1562 return new_c
1563
1564 new_c = save_and_restore(c, True)
1565 self.assertEquals(len(new_c), 6) # none discarded
1566 self.assert_("name='foo1', value='bar'" in repr(new_c))
1567
1568 new_c = save_and_restore(c, False)
1569 self.assertEquals(len(new_c), 4) # 2 of them discarded on save
1570 self.assert_("name='foo1', value='bar'" in repr(new_c))
1571
1572 def test_netscape_misc(self):
1573 # Some additional Netscape cookies tests.
1574 from cookielib import CookieJar
1575 from urllib2 import Request
1576
1577 c = CookieJar()
1578 headers = []
1579 req = Request("http://foo.bar.acme.com/foo")
1580
1581 # Netscape allows a host part that contains dots
1582 headers.append("Set-Cookie: Customer=WILE_E_COYOTE; domain=.acme.com")
1583 res = FakeResponse(headers, "http://www.acme.com/foo")
1584 c.extract_cookies(res, req)
1585
1586 # and that the domain is the same as the host without adding a leading
1587 # dot to the domain. Should not quote even if strange chars are used
1588 # in the cookie value.
1589 headers.append("Set-Cookie: PART_NUMBER=3,4; domain=foo.bar.acme.com")
1590 res = FakeResponse(headers, "http://www.acme.com/foo")
1591 c.extract_cookies(res, req)
1592
1593 req = Request("http://foo.bar.acme.com/foo")
1594 c.add_cookie_header(req)
1595 self.assert_(
1596 "PART_NUMBER=3,4" in req.get_header("Cookie") and
1597 "Customer=WILE_E_COYOTE" in req.get_header("Cookie"))
1598
1599 def test_intranet_domains_2965(self):
1600 # Test handling of local intranet hostnames without a dot.
1601 from cookielib import CookieJar, DefaultCookiePolicy
1602
1603 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1604 interact_2965(c, "http://example/",
1605 "foo1=bar; PORT; Discard; Version=1;")
1606 cookie = interact_2965(c, "http://example/",
1607 'foo2=bar; domain=".local"; Version=1')
1608 self.assert_("foo1=bar" in cookie)
1609
1610 interact_2965(c, "http://example/", 'foo3=bar; Version=1')
1611 cookie = interact_2965(c, "http://example/")
1612 self.assert_("foo2=bar" in cookie and len(c) == 3)
1613
1614 def test_intranet_domains_ns(self):
1615 from cookielib import CookieJar, DefaultCookiePolicy
1616
1617 c = CookieJar(DefaultCookiePolicy(rfc2965 = False))
1618 interact_netscape(c, "http://example/", "foo1=bar")
1619 cookie = interact_netscape(c, "http://example/",
1620 'foo2=bar; domain=.local')
1621 self.assertEquals(len(c), 2)
1622 self.assert_("foo1=bar" in cookie)
1623
1624 cookie = interact_netscape(c, "http://example/")
1625 self.assert_("foo2=bar" in cookie)
1626 self.assertEquals(len(c), 2)
1627
1628 def test_empty_path(self):
1629 from cookielib import CookieJar, DefaultCookiePolicy
1630 from urllib2 import Request
1631
1632 # Test for empty path
1633 # Broken web-server ORION/1.3.38 returns to the client response like
1634 #
1635 # Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=
1636 #
1637 # ie. with Path set to nothing.
1638 # In this case, extract_cookies() must set cookie to / (root)
1639 c = CookieJar(DefaultCookiePolicy(rfc2965 = True))
1640 headers = []
1641
1642 req = Request("http://www.ants.com/")
1643 headers.append("Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=")
1644 res = FakeResponse(headers, "http://www.ants.com/")
1645 c.extract_cookies(res, req)
1646
1647 req = Request("http://www.ants.com/")
1648 c.add_cookie_header(req)
1649
1650 self.assertEquals(req.get_header("Cookie"),
1651 "JSESSIONID=ABCDERANDOM123")
1652 self.assertEquals(req.get_header("Cookie2"), '$Version="1"')
1653
1654 # missing path in the request URI
1655 req = Request("http://www.ants.com:8080")
1656 c.add_cookie_header(req)
1657
1658 self.assertEquals(req.get_header("Cookie"),
1659 "JSESSIONID=ABCDERANDOM123")
1660 self.assertEquals(req.get_header("Cookie2"), '$Version="1"')
1661
1662 def test_session_cookies(self):
1663 from cookielib import CookieJar
1664 from urllib2 import Request
1665
1666 year_plus_one = time.localtime()[0] + 1
1667
1668 # Check session cookies are deleted properly by
1669 # CookieJar.clear_session_cookies method
1670
1671 req = Request('http://www.perlmeister.com/scripts')
1672 headers = []
1673 headers.append("Set-Cookie: s1=session;Path=/scripts")
1674 headers.append("Set-Cookie: p1=perm; Domain=.perlmeister.com;"
1675 "Path=/;expires=Fri, 02-Feb-%d 23:24:20 GMT" %
1676 year_plus_one)
1677 headers.append("Set-Cookie: p2=perm;Path=/;expires=Fri, "
1678 "02-Feb-%d 23:24:20 GMT" % year_plus_one)
1679 headers.append("Set-Cookie: s2=session;Path=/scripts;"
1680 "Domain=.perlmeister.com")
1681 headers.append('Set-Cookie2: s3=session;Version=1;Discard;Path="/"')
1682 res = FakeResponse(headers, 'http://www.perlmeister.com/scripts')
1683
1684 c = CookieJar()
1685 c.extract_cookies(res, req)
1686 # How many session/permanent cookies do we have?
1687 counter = {"session_after": 0,
1688 "perm_after": 0,
1689 "session_before": 0,
1690 "perm_before": 0}
1691 for cookie in c:
1692 key = "%s_before" % cookie.value
1693 counter[key] = counter[key] + 1
1694 c.clear_session_cookies()
1695 # How many now?
1696 for cookie in c:
1697 key = "%s_after" % cookie.value
1698 counter[key] = counter[key] + 1
1699
1700 self.assert_(not (
1701 # a permanent cookie got lost accidently
1702 counter["perm_after"] != counter["perm_before"] or
1703 # a session cookie hasn't been cleared
1704 counter["session_after"] != 0 or
1705 # we didn't have session cookies in the first place
1706 counter["session_before"] == 0))
1707
1708
1709def test_main(verbose=None):
1710 from test import test_sets
1711 test_support.run_unittest(
1712 DateTimeTests,
1713 HeaderTests,
1714 CookieTests,
Martin v. Löwisc5574e82005-03-03 10:57:37 +00001715 FileCookieJarTests,
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001716 LWPCookieTests,
1717 )
1718
1719if __name__ == "__main__":
1720 test_main(verbose=True)