blob: f0c66837ce63ab905eff4d0c00d58fa23384c8d3 [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
389 def test_ns_parser(self):
390 from cookielib import CookieJar, DEFAULT_HTTP_PORT
391
392 c = CookieJar()
393 interact_netscape(c, "http://www.acme.com/",
394 'spam=eggs; DoMain=.acme.com; port; blArgh="feep"')
395 interact_netscape(c, "http://www.acme.com/", 'ni=ni; port=80,8080')
396 interact_netscape(c, "http://www.acme.com:80/", 'nini=ni')
397 interact_netscape(c, "http://www.acme.com:80/", 'foo=bar; expires=')
398 interact_netscape(c, "http://www.acme.com:80/", 'spam=eggs; '
399 'expires="Foo Bar 25 33:22:11 3022"')
400
401 cookie = c._cookies[".acme.com"]["/"]["spam"]
402 self.assertEquals(cookie.domain, ".acme.com")
403 self.assert_(cookie.domain_specified)
404 self.assertEquals(cookie.port, DEFAULT_HTTP_PORT)
405 self.assert_(not cookie.port_specified)
406 # case is preserved
407 self.assert_(cookie.has_nonstandard_attr("blArgh") and
408 not cookie.has_nonstandard_attr("blargh"))
409
410 cookie = c._cookies["www.acme.com"]["/"]["ni"]
411 self.assertEquals(cookie.domain, "www.acme.com")
412 self.assert_(not cookie.domain_specified)
413 self.assertEquals(cookie.port, "80,8080")
414 self.assert_(cookie.port_specified)
415
416 cookie = c._cookies["www.acme.com"]["/"]["nini"]
417 self.assert_(cookie.port is None)
418 self.assert_(not cookie.port_specified)
419
420 # invalid expires should not cause cookie to be dropped
421 foo = c._cookies["www.acme.com"]["/"]["foo"]
422 spam = c._cookies["www.acme.com"]["/"]["foo"]
423 self.assert_(foo.expires is None)
424 self.assert_(spam.expires is None)
425
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000426 def test_ns_parser_special_names(self):
427 # names such as 'expires' are not special in first name=value pair
428 # of Set-Cookie: header
429 from cookielib import CookieJar
430
431 c = CookieJar()
432 interact_netscape(c, "http://www.acme.com/", 'expires=eggs')
433 interact_netscape(c, "http://www.acme.com/", 'version=eggs; spam=eggs')
434
435 cookies = c._cookies["www.acme.com"]["/"]
436 self.assert_('expires' in cookies)
437 self.assert_('version' in cookies)
438
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000439 def test_expires(self):
440 from cookielib import time2netscape, CookieJar
441
442 # if expires is in future, keep cookie...
443 c = CookieJar()
444 future = time2netscape(time.time()+3600)
445 interact_netscape(c, "http://www.acme.com/", 'spam="bar"; expires=%s' %
446 future)
447 self.assertEquals(len(c), 1)
448 now = time2netscape(time.time()-1)
449 # ... and if in past or present, discard it
450 interact_netscape(c, "http://www.acme.com/", 'foo="eggs"; expires=%s' %
451 now)
452 h = interact_netscape(c, "http://www.acme.com/")
453 self.assertEquals(len(c), 1)
454 self.assert_('spam="bar"' in h and "foo" not in h)
455
456 # max-age takes precedence over expires, and zero max-age is request to
457 # delete both new cookie and any old matching cookie
458 interact_netscape(c, "http://www.acme.com/", 'eggs="bar"; expires=%s' %
459 future)
460 interact_netscape(c, "http://www.acme.com/", 'bar="bar"; expires=%s' %
461 future)
462 self.assertEquals(len(c), 3)
463 interact_netscape(c, "http://www.acme.com/", 'eggs="bar"; '
464 'expires=%s; max-age=0' % future)
465 interact_netscape(c, "http://www.acme.com/", 'bar="bar"; '
466 'max-age=0; expires=%s' % future)
467 h = interact_netscape(c, "http://www.acme.com/")
468 self.assertEquals(len(c), 1)
469
470 # test expiry at end of session for cookies with no expires attribute
471 interact_netscape(c, "http://www.rhubarb.net/", 'whum="fizz"')
472 self.assertEquals(len(c), 2)
473 c.clear_session_cookies()
474 self.assertEquals(len(c), 1)
475 self.assert_('spam="bar"' in h)
476
477 # XXX RFC 2965 expiry rules (some apply to V0 too)
478
479 def test_default_path(self):
480 from cookielib import CookieJar, DefaultCookiePolicy
481
482 # RFC 2965
483 pol = DefaultCookiePolicy(rfc2965=True)
484
485 c = CookieJar(pol)
486 interact_2965(c, "http://www.acme.com/", 'spam="bar"; Version="1"')
487 self.assert_("/" in c._cookies["www.acme.com"])
488
489 c = CookieJar(pol)
490 interact_2965(c, "http://www.acme.com/blah", 'eggs="bar"; Version="1"')
491 self.assert_("/" in c._cookies["www.acme.com"])
492
493 c = CookieJar(pol)
494 interact_2965(c, "http://www.acme.com/blah/rhubarb",
495 'eggs="bar"; Version="1"')
496 self.assert_("/blah/" in c._cookies["www.acme.com"])
497
498 c = CookieJar(pol)
499 interact_2965(c, "http://www.acme.com/blah/rhubarb/",
500 'eggs="bar"; Version="1"')
501 self.assert_("/blah/rhubarb/" in c._cookies["www.acme.com"])
502
503 # Netscape
504
505 c = CookieJar()
506 interact_netscape(c, "http://www.acme.com/", 'spam="bar"')
507 self.assert_("/" in c._cookies["www.acme.com"])
508
509 c = CookieJar()
510 interact_netscape(c, "http://www.acme.com/blah", 'eggs="bar"')
511 self.assert_("/" in c._cookies["www.acme.com"])
512
513 c = CookieJar()
514 interact_netscape(c, "http://www.acme.com/blah/rhubarb", 'eggs="bar"')
515 self.assert_("/blah" in c._cookies["www.acme.com"])
516
517 c = CookieJar()
518 interact_netscape(c, "http://www.acme.com/blah/rhubarb/", 'eggs="bar"')
519 self.assert_("/blah/rhubarb" in c._cookies["www.acme.com"])
520
521 def test_escape_path(self):
522 from cookielib import escape_path
523 cases = [
524 # quoted safe
525 ("/foo%2f/bar", "/foo%2F/bar"),
526 ("/foo%2F/bar", "/foo%2F/bar"),
527 # quoted %
528 ("/foo%%/bar", "/foo%%/bar"),
529 # quoted unsafe
530 ("/fo%19o/bar", "/fo%19o/bar"),
531 ("/fo%7do/bar", "/fo%7Do/bar"),
532 # unquoted safe
533 ("/foo/bar&", "/foo/bar&"),
534 ("/foo//bar", "/foo//bar"),
535 ("\176/foo/bar", "\176/foo/bar"),
536 # unquoted unsafe
537 ("/foo\031/bar", "/foo%19/bar"),
538 ("/\175foo/bar", "/%7Dfoo/bar"),
539 # unicode
540 (u"/foo/bar\uabcd", "/foo/bar%EA%AF%8D"), # UTF-8 encoded
541 ]
542 for arg, result in cases:
543 self.assertEquals(escape_path(arg), result)
544
545 def test_request_path(self):
546 from urllib2 import Request
547 from cookielib import request_path
548 # with parameters
549 req = Request("http://www.example.com/rheum/rhaponicum;"
550 "foo=bar;sing=song?apples=pears&spam=eggs#ni")
551 self.assertEquals(request_path(req), "/rheum/rhaponicum;"
552 "foo=bar;sing=song?apples=pears&spam=eggs#ni")
553 # without parameters
554 req = Request("http://www.example.com/rheum/rhaponicum?"
555 "apples=pears&spam=eggs#ni")
556 self.assertEquals(request_path(req), "/rheum/rhaponicum?"
557 "apples=pears&spam=eggs#ni")
558 # missing final slash
559 req = Request("http://www.example.com")
560 self.assertEquals(request_path(req), "/")
561
562 def test_request_port(self):
563 from urllib2 import Request
564 from cookielib import request_port, DEFAULT_HTTP_PORT
565 req = Request("http://www.acme.com:1234/",
566 headers={"Host": "www.acme.com:4321"})
567 self.assertEquals(request_port(req), "1234")
568 req = Request("http://www.acme.com/",
569 headers={"Host": "www.acme.com:4321"})
570 self.assertEquals(request_port(req), DEFAULT_HTTP_PORT)
571
572 def test_request_host(self):
573 from urllib2 import Request
574 from cookielib import request_host
575 # this request is illegal (RFC2616, 14.2.3)
576 req = Request("http://1.1.1.1/",
577 headers={"Host": "www.acme.com:80"})
578 # libwww-perl wants this response, but that seems wrong (RFC 2616,
579 # section 5.2, point 1., and RFC 2965 section 1, paragraph 3)
580 #self.assertEquals(request_host(req), "www.acme.com")
581 self.assertEquals(request_host(req), "1.1.1.1")
582 req = Request("http://www.acme.com/",
583 headers={"Host": "irrelevant.com"})
584 self.assertEquals(request_host(req), "www.acme.com")
585 # not actually sure this one is valid Request object, so maybe should
586 # remove test for no host in url in request_host function?
587 req = Request("/resource.html",
588 headers={"Host": "www.acme.com"})
589 self.assertEquals(request_host(req), "www.acme.com")
590 # port shouldn't be in request-host
591 req = Request("http://www.acme.com:2345/resource.html",
592 headers={"Host": "www.acme.com:5432"})
593 self.assertEquals(request_host(req), "www.acme.com")
594
595 def test_is_HDN(self):
596 from cookielib import is_HDN
597 self.assert_(is_HDN("foo.bar.com"))
598 self.assert_(is_HDN("1foo2.3bar4.5com"))
599 self.assert_(not is_HDN("192.168.1.1"))
600 self.assert_(not is_HDN(""))
601 self.assert_(not is_HDN("."))
602 self.assert_(not is_HDN(".foo.bar.com"))
603 self.assert_(not is_HDN("..foo"))
604 self.assert_(not is_HDN("foo."))
605
606 def test_reach(self):
607 from cookielib import reach
608 self.assertEquals(reach("www.acme.com"), ".acme.com")
609 self.assertEquals(reach("acme.com"), "acme.com")
610 self.assertEquals(reach("acme.local"), ".local")
611 self.assertEquals(reach(".local"), ".local")
612 self.assertEquals(reach(".com"), ".com")
613 self.assertEquals(reach("."), ".")
614 self.assertEquals(reach(""), "")
615 self.assertEquals(reach("192.168.0.1"), "192.168.0.1")
616
617 def test_domain_match(self):
618 from cookielib import domain_match, user_domain_match
619 self.assert_(domain_match("192.168.1.1", "192.168.1.1"))
620 self.assert_(not domain_match("192.168.1.1", ".168.1.1"))
621 self.assert_(domain_match("x.y.com", "x.Y.com"))
622 self.assert_(domain_match("x.y.com", ".Y.com"))
623 self.assert_(not domain_match("x.y.com", "Y.com"))
624 self.assert_(domain_match("a.b.c.com", ".c.com"))
625 self.assert_(not domain_match(".c.com", "a.b.c.com"))
626 self.assert_(domain_match("example.local", ".local"))
627 self.assert_(not domain_match("blah.blah", ""))
628 self.assert_(not domain_match("", ".rhubarb.rhubarb"))
629 self.assert_(domain_match("", ""))
630
631 self.assert_(user_domain_match("acme.com", "acme.com"))
632 self.assert_(not user_domain_match("acme.com", ".acme.com"))
633 self.assert_(user_domain_match("rhubarb.acme.com", ".acme.com"))
634 self.assert_(user_domain_match("www.rhubarb.acme.com", ".acme.com"))
635 self.assert_(user_domain_match("x.y.com", "x.Y.com"))
636 self.assert_(user_domain_match("x.y.com", ".Y.com"))
637 self.assert_(not user_domain_match("x.y.com", "Y.com"))
638 self.assert_(user_domain_match("y.com", "Y.com"))
639 self.assert_(not user_domain_match(".y.com", "Y.com"))
640 self.assert_(user_domain_match(".y.com", ".Y.com"))
641 self.assert_(user_domain_match("x.y.com", ".com"))
642 self.assert_(not user_domain_match("x.y.com", "com"))
643 self.assert_(not user_domain_match("x.y.com", "m"))
644 self.assert_(not user_domain_match("x.y.com", ".m"))
645 self.assert_(not user_domain_match("x.y.com", ""))
646 self.assert_(not user_domain_match("x.y.com", "."))
647 self.assert_(user_domain_match("192.168.1.1", "192.168.1.1"))
648 # not both HDNs, so must string-compare equal to match
649 self.assert_(not user_domain_match("192.168.1.1", ".168.1.1"))
650 self.assert_(not user_domain_match("192.168.1.1", "."))
651 # empty string is a special case
652 self.assert_(not user_domain_match("192.168.1.1", ""))
653
654 def test_wrong_domain(self):
655 # Cookies whose effective request-host name does not domain-match the
656 # domain are rejected.
657
658 # XXX far from complete
659 from cookielib import CookieJar
660 c = CookieJar()
661 interact_2965(c, "http://www.nasty.com/",
662 'foo=bar; domain=friendly.org; Version="1"')
663 self.assertEquals(len(c), 0)
664
665 def test_two_component_domain_ns(self):
666 # Netscape: .www.bar.com, www.bar.com, .bar.com, bar.com, no domain
667 # should all get accepted, as should .acme.com, acme.com and no domain
668 # for 2-component domains like acme.com.
669 from cookielib import CookieJar, DefaultCookiePolicy
670
671 c = CookieJar()
672
673 # two-component V0 domain is OK
674 interact_netscape(c, "http://foo.net/", 'ns=bar')
675 self.assertEquals(len(c), 1)
676 self.assertEquals(c._cookies["foo.net"]["/"]["ns"].value, "bar")
677 self.assertEquals(interact_netscape(c, "http://foo.net/"), "ns=bar")
678 # *will* be returned to any other domain (unlike RFC 2965)...
679 self.assertEquals(interact_netscape(c, "http://www.foo.net/"),
680 "ns=bar")
681 # ...unless requested otherwise
682 pol = DefaultCookiePolicy(
683 strict_ns_domain=DefaultCookiePolicy.DomainStrictNonDomain)
684 c.set_policy(pol)
685 self.assertEquals(interact_netscape(c, "http://www.foo.net/"), "")
686
687 # unlike RFC 2965, even explicit two-component domain is OK,
688 # because .foo.net matches foo.net
689 interact_netscape(c, "http://foo.net/foo/",
690 'spam1=eggs; domain=foo.net')
691 # even if starts with a dot -- in NS rules, .foo.net matches foo.net!
692 interact_netscape(c, "http://foo.net/foo/bar/",
693 'spam2=eggs; domain=.foo.net')
694 self.assertEquals(len(c), 3)
695 self.assertEquals(c._cookies[".foo.net"]["/foo"]["spam1"].value,
696 "eggs")
697 self.assertEquals(c._cookies[".foo.net"]["/foo/bar"]["spam2"].value,
698 "eggs")
699 self.assertEquals(interact_netscape(c, "http://foo.net/foo/bar/"),
700 "spam2=eggs; spam1=eggs; ns=bar")
701
702 # top-level domain is too general
703 interact_netscape(c, "http://foo.net/", 'nini="ni"; domain=.net')
704 self.assertEquals(len(c), 3)
705
706## # Netscape protocol doesn't allow non-special top level domains (such
707## # as co.uk) in the domain attribute unless there are at least three
708## # dots in it.
709 # Oh yes it does! Real implementations don't check this, and real
710 # cookies (of course) rely on that behaviour.
711 interact_netscape(c, "http://foo.co.uk", 'nasty=trick; domain=.co.uk')
712## self.assertEquals(len(c), 2)
713 self.assertEquals(len(c), 4)
714
715 def test_two_component_domain_rfc2965(self):
716 from cookielib import CookieJar, DefaultCookiePolicy
717
718 pol = DefaultCookiePolicy(rfc2965=True)
719 c = CookieJar(pol)
720
721 # two-component V1 domain is OK
722 interact_2965(c, "http://foo.net/", 'foo=bar; Version="1"')
723 self.assertEquals(len(c), 1)
724 self.assertEquals(c._cookies["foo.net"]["/"]["foo"].value, "bar")
725 self.assertEquals(interact_2965(c, "http://foo.net/"),
726 "$Version=1; foo=bar")
727 # won't be returned to any other domain (because domain was implied)
728 self.assertEquals(interact_2965(c, "http://www.foo.net/"), "")
729
730 # unless domain is given explicitly, because then it must be
731 # rewritten to start with a dot: foo.net --> .foo.net, which does
732 # not domain-match foo.net
733 interact_2965(c, "http://foo.net/foo",
734 'spam=eggs; domain=foo.net; path=/foo; Version="1"')
735 self.assertEquals(len(c), 1)
736 self.assertEquals(interact_2965(c, "http://foo.net/foo"),
737 "$Version=1; foo=bar")
738
739 # explicit foo.net from three-component domain www.foo.net *does* get
740 # set, because .foo.net domain-matches .foo.net
741 interact_2965(c, "http://www.foo.net/foo/",
742 'spam=eggs; domain=foo.net; Version="1"')
743 self.assertEquals(c._cookies[".foo.net"]["/foo/"]["spam"].value,
744 "eggs")
745 self.assertEquals(len(c), 2)
746 self.assertEquals(interact_2965(c, "http://foo.net/foo/"),
747 "$Version=1; foo=bar")
748 self.assertEquals(interact_2965(c, "http://www.foo.net/foo/"),
749 '$Version=1; spam=eggs; $Domain="foo.net"')
750
751 # top-level domain is too general
752 interact_2965(c, "http://foo.net/",
753 'ni="ni"; domain=".net"; Version="1"')
754 self.assertEquals(len(c), 2)
755
756 # RFC 2965 doesn't require blocking this
757 interact_2965(c, "http://foo.co.uk/",
758 'nasty=trick; domain=.co.uk; Version="1"')
759 self.assertEquals(len(c), 3)
760
761 def test_domain_allow(self):
762 from cookielib import CookieJar, DefaultCookiePolicy
763 from urllib2 import Request
764
765 c = CookieJar(policy=DefaultCookiePolicy(
766 blocked_domains=["acme.com"],
767 allowed_domains=["www.acme.com"]))
768
769 req = Request("http://acme.com/")
770 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
771 res = FakeResponse(headers, "http://acme.com/")
772 c.extract_cookies(res, req)
773 self.assertEquals(len(c), 0)
774
775 req = Request("http://www.acme.com/")
776 res = FakeResponse(headers, "http://www.acme.com/")
777 c.extract_cookies(res, req)
778 self.assertEquals(len(c), 1)
779
780 req = Request("http://www.coyote.com/")
781 res = FakeResponse(headers, "http://www.coyote.com/")
782 c.extract_cookies(res, req)
783 self.assertEquals(len(c), 1)
784
785 # set a cookie with non-allowed domain...
786 req = Request("http://www.coyote.com/")
787 res = FakeResponse(headers, "http://www.coyote.com/")
788 cookies = c.make_cookies(res, req)
789 c.set_cookie(cookies[0])
790 self.assertEquals(len(c), 2)
791 # ... and check is doesn't get returned
792 c.add_cookie_header(req)
793 self.assert_(not req.has_header("Cookie"))
794
795 def test_domain_block(self):
796 from cookielib import CookieJar, DefaultCookiePolicy
797 from urllib2 import Request
798
799 pol = DefaultCookiePolicy(
800 rfc2965=True, blocked_domains=[".acme.com"])
801 c = CookieJar(policy=pol)
802 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
803
804 req = Request("http://www.acme.com/")
805 res = FakeResponse(headers, "http://www.acme.com/")
806 c.extract_cookies(res, req)
807 self.assertEquals(len(c), 0)
808
809 p = pol.set_blocked_domains(["acme.com"])
810 c.extract_cookies(res, req)
811 self.assertEquals(len(c), 1)
812
813 c.clear()
814 req = Request("http://www.roadrunner.net/")
815 res = FakeResponse(headers, "http://www.roadrunner.net/")
816 c.extract_cookies(res, req)
817 self.assertEquals(len(c), 1)
818 req = Request("http://www.roadrunner.net/")
819 c.add_cookie_header(req)
820 self.assert_((req.has_header("Cookie") and
821 req.has_header("Cookie2")))
822
823 c.clear()
824 pol.set_blocked_domains([".acme.com"])
825 c.extract_cookies(res, req)
826 self.assertEquals(len(c), 1)
827
828 # set a cookie with blocked domain...
829 req = Request("http://www.acme.com/")
830 res = FakeResponse(headers, "http://www.acme.com/")
831 cookies = c.make_cookies(res, req)
832 c.set_cookie(cookies[0])
833 self.assertEquals(len(c), 2)
834 # ... and check is doesn't get returned
835 c.add_cookie_header(req)
836 self.assert_(not req.has_header("Cookie"))
837
838 def test_secure(self):
839 from cookielib import CookieJar, DefaultCookiePolicy
840
841 for ns in True, False:
842 for whitespace in " ", "":
843 c = CookieJar()
844 if ns:
845 pol = DefaultCookiePolicy(rfc2965=False)
846 int = interact_netscape
847 vs = ""
848 else:
849 pol = DefaultCookiePolicy(rfc2965=True)
850 int = interact_2965
851 vs = "; Version=1"
852 c.set_policy(pol)
853 url = "http://www.acme.com/"
854 int(c, url, "foo1=bar%s%s" % (vs, whitespace))
855 int(c, url, "foo2=bar%s; secure%s" % (vs, whitespace))
856 self.assert_(
857 not c._cookies["www.acme.com"]["/"]["foo1"].secure,
858 "non-secure cookie registered secure")
859 self.assert_(
860 c._cookies["www.acme.com"]["/"]["foo2"].secure,
861 "secure cookie registered non-secure")
862
863 def test_quote_cookie_value(self):
864 from cookielib import CookieJar, DefaultCookiePolicy
865 c = CookieJar(policy=DefaultCookiePolicy(rfc2965=True))
866 interact_2965(c, "http://www.acme.com/", r'foo=\b"a"r; Version=1')
867 h = interact_2965(c, "http://www.acme.com/")
868 self.assertEquals(h, r'$Version=1; foo=\\b\"a\"r')
869
870 def test_missing_final_slash(self):
871 # Missing slash from request URL's abs_path should be assumed present.
872 from cookielib import CookieJar, DefaultCookiePolicy
873 from urllib2 import Request
874 url = "http://www.acme.com"
875 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
876 interact_2965(c, url, "foo=bar; Version=1")
877 req = Request(url)
878 self.assertEquals(len(c), 1)
879 c.add_cookie_header(req)
880 self.assert_(req.has_header("Cookie"))
881
882 def test_domain_mirror(self):
883 from cookielib import CookieJar, DefaultCookiePolicy
884
885 pol = DefaultCookiePolicy(rfc2965=True)
886
887 c = CookieJar(pol)
888 url = "http://foo.bar.com/"
889 interact_2965(c, url, "spam=eggs; Version=1")
890 h = interact_2965(c, url)
891 self.assert_("Domain" not in h,
892 "absent domain returned with domain present")
893
894 c = CookieJar(pol)
895 url = "http://foo.bar.com/"
896 interact_2965(c, url, 'spam=eggs; Version=1; Domain=.bar.com')
897 h = interact_2965(c, url)
898 self.assert_('$Domain=".bar.com"' in h, "domain not returned")
899
900 c = CookieJar(pol)
901 url = "http://foo.bar.com/"
902 # note missing initial dot in Domain
903 interact_2965(c, url, 'spam=eggs; Version=1; Domain=bar.com')
904 h = interact_2965(c, url)
905 self.assert_('$Domain="bar.com"' in h, "domain not returned")
906
907 def test_path_mirror(self):
908 from cookielib import CookieJar, DefaultCookiePolicy
909
910 pol = DefaultCookiePolicy(rfc2965=True)
911
912 c = CookieJar(pol)
913 url = "http://foo.bar.com/"
914 interact_2965(c, url, "spam=eggs; Version=1")
915 h = interact_2965(c, url)
916 self.assert_("Path" not in h,
917 "absent path returned with path present")
918
919 c = CookieJar(pol)
920 url = "http://foo.bar.com/"
921 interact_2965(c, url, 'spam=eggs; Version=1; Path=/')
922 h = interact_2965(c, url)
923 self.assert_('$Path="/"' in h, "path not returned")
924
925 def test_port_mirror(self):
926 from cookielib import CookieJar, DefaultCookiePolicy
927
928 pol = DefaultCookiePolicy(rfc2965=True)
929
930 c = CookieJar(pol)
931 url = "http://foo.bar.com/"
932 interact_2965(c, url, "spam=eggs; Version=1")
933 h = interact_2965(c, url)
934 self.assert_("Port" not in h,
935 "absent port returned with port present")
936
937 c = CookieJar(pol)
938 url = "http://foo.bar.com/"
939 interact_2965(c, url, "spam=eggs; Version=1; Port")
940 h = interact_2965(c, url)
941 self.assert_(re.search("\$Port([^=]|$)", h),
942 "port with no value not returned with no value")
943
944 c = CookieJar(pol)
945 url = "http://foo.bar.com/"
946 interact_2965(c, url, 'spam=eggs; Version=1; Port="80"')
947 h = interact_2965(c, url)
948 self.assert_('$Port="80"' in h,
949 "port with single value not returned with single value")
950
951 c = CookieJar(pol)
952 url = "http://foo.bar.com/"
953 interact_2965(c, url, 'spam=eggs; Version=1; Port="80,8080"')
954 h = interact_2965(c, url)
955 self.assert_('$Port="80,8080"' in h,
956 "port with multiple values not returned with multiple "
957 "values")
958
959 def test_no_return_comment(self):
960 from cookielib import CookieJar, DefaultCookiePolicy
961
962 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
963 url = "http://foo.bar.com/"
964 interact_2965(c, url, 'spam=eggs; Version=1; '
965 'Comment="does anybody read these?"; '
966 'CommentURL="http://foo.bar.net/comment.html"')
967 h = interact_2965(c, url)
968 self.assert_(
969 "Comment" not in h,
970 "Comment or CommentURL cookie-attributes returned to server")
971
972 def test_Cookie_iterator(self):
973 from cookielib import CookieJar, Cookie, DefaultCookiePolicy
974
975 cs = CookieJar(DefaultCookiePolicy(rfc2965=True))
976 # add some random cookies
977 interact_2965(cs, "http://blah.spam.org/", 'foo=eggs; Version=1; '
978 'Comment="does anybody read these?"; '
979 'CommentURL="http://foo.bar.net/comment.html"')
980 interact_netscape(cs, "http://www.acme.com/blah/", "spam=bar; secure")
981 interact_2965(cs, "http://www.acme.com/blah/",
982 "foo=bar; secure; Version=1")
983 interact_2965(cs, "http://www.acme.com/blah/",
984 "foo=bar; path=/; Version=1")
985 interact_2965(cs, "http://www.sol.no",
986 r'bang=wallop; version=1; domain=".sol.no"; '
987 r'port="90,100, 80,8080"; '
988 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "')
989
990 versions = [1, 1, 1, 0, 1]
991 names = ["bang", "foo", "foo", "spam", "foo"]
992 domains = [".sol.no", "blah.spam.org", "www.acme.com",
993 "www.acme.com", "www.acme.com"]
994 paths = ["/", "/", "/", "/blah", "/blah/"]
995
996 for i in range(4):
997 i = 0
998 for c in cs:
999 self.assert_(isinstance(c, Cookie))
1000 self.assertEquals(c.version, versions[i])
1001 self.assertEquals(c.name, names[i])
1002 self.assertEquals(c.domain, domains[i])
1003 self.assertEquals(c.path, paths[i])
1004 i = i + 1
1005
1006 def test_parse_ns_headers(self):
1007 from cookielib import parse_ns_headers
1008
1009 # missing domain value (invalid cookie)
1010 self.assertEquals(
1011 parse_ns_headers(["foo=bar; path=/; domain"]),
1012 [[("foo", "bar"),
1013 ("path", "/"), ("domain", None), ("version", "0")]]
1014 )
1015 # invalid expires value
1016 self.assertEquals(
1017 parse_ns_headers(["foo=bar; expires=Foo Bar 12 33:22:11 2000"]),
1018 [[("foo", "bar"), ("expires", None), ("version", "0")]]
1019 )
1020 # missing cookie value (valid cookie)
1021 self.assertEquals(
1022 parse_ns_headers(["foo"]),
1023 [[("foo", None), ("version", "0")]]
1024 )
1025 # shouldn't add version if header is empty
1026 self.assertEquals(parse_ns_headers([""]), [])
1027
1028 def test_bad_cookie_header(self):
1029
1030 def cookiejar_from_cookie_headers(headers):
1031 from cookielib import CookieJar
1032 from urllib2 import Request
1033 c = CookieJar()
1034 req = Request("http://www.example.com/")
1035 r = FakeResponse(headers, "http://www.example.com/")
1036 c.extract_cookies(r, req)
1037 return c
1038
1039 # none of these bad headers should cause an exception to be raised
1040 for headers in [
1041 ["Set-Cookie: "], # actually, nothing wrong with this
1042 ["Set-Cookie2: "], # ditto
1043 # missing domain value
1044 ["Set-Cookie2: a=foo; path=/; Version=1; domain"],
1045 # bad max-age
1046 ["Set-Cookie: b=foo; max-age=oops"],
1047 ]:
1048 c = cookiejar_from_cookie_headers(headers)
1049 # these bad cookies shouldn't be set
1050 self.assertEquals(len(c), 0)
1051
1052 # cookie with invalid expires is treated as session cookie
1053 headers = ["Set-Cookie: c=foo; expires=Foo Bar 12 33:22:11 2000"]
1054 c = cookiejar_from_cookie_headers(headers)
1055 cookie = c._cookies["www.example.com"]["/"]["c"]
1056 self.assert_(cookie.expires is None)
1057
1058
1059class LWPCookieTests(TestCase):
1060 # Tests taken from libwww-perl, with a few modifications and additions.
1061
1062 def test_netscape_example_1(self):
1063 from cookielib import CookieJar, DefaultCookiePolicy
1064 from urllib2 import Request
1065
1066 #-------------------------------------------------------------------
1067 # First we check that it works for the original example at
1068 # http://www.netscape.com/newsref/std/cookie_spec.html
1069
1070 # Client requests a document, and receives in the response:
1071 #
1072 # Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
1073 #
1074 # When client requests a URL in path "/" on this server, it sends:
1075 #
1076 # Cookie: CUSTOMER=WILE_E_COYOTE
1077 #
1078 # Client requests a document, and receives in the response:
1079 #
1080 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
1081 #
1082 # When client requests a URL in path "/" on this server, it sends:
1083 #
1084 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
1085 #
1086 # Client receives:
1087 #
1088 # Set-Cookie: SHIPPING=FEDEX; path=/fo
1089 #
1090 # When client requests a URL in path "/" on this server, it sends:
1091 #
1092 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
1093 #
1094 # When client requests a URL in path "/foo" on this server, it sends:
1095 #
1096 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX
1097 #
1098 # The last Cookie is buggy, because both specifications say that the
1099 # most specific cookie must be sent first. SHIPPING=FEDEX is the
1100 # most specific and should thus be first.
1101
1102 year_plus_one = time.localtime()[0] + 1
1103
1104 headers = []
1105
1106 c = CookieJar(DefaultCookiePolicy(rfc2965 = True))
1107
1108 #req = Request("http://1.1.1.1/",
1109 # headers={"Host": "www.acme.com:80"})
1110 req = Request("http://www.acme.com:80/",
1111 headers={"Host": "www.acme.com:80"})
1112
1113 headers.append(
1114 "Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/ ; "
1115 "expires=Wednesday, 09-Nov-%d 23:12:40 GMT" % year_plus_one)
1116 res = FakeResponse(headers, "http://www.acme.com/")
1117 c.extract_cookies(res, req)
1118
1119 req = Request("http://www.acme.com/")
1120 c.add_cookie_header(req)
1121
1122 self.assertEqual(req.get_header("Cookie"), "CUSTOMER=WILE_E_COYOTE")
1123 self.assertEqual(req.get_header("Cookie2"), '$Version="1"')
1124
1125 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/")
1126 res = FakeResponse(headers, "http://www.acme.com/")
1127 c.extract_cookies(res, req)
1128
1129 req = Request("http://www.acme.com/foo/bar")
1130 c.add_cookie_header(req)
1131
1132 h = req.get_header("Cookie")
1133 self.assert_("PART_NUMBER=ROCKET_LAUNCHER_0001" in h and
1134 "CUSTOMER=WILE_E_COYOTE" in h)
1135
1136 headers.append('Set-Cookie: SHIPPING=FEDEX; path=/foo')
1137 res = FakeResponse(headers, "http://www.acme.com")
1138 c.extract_cookies(res, req)
1139
1140 req = Request("http://www.acme.com/")
1141 c.add_cookie_header(req)
1142
1143 h = req.get_header("Cookie")
1144 self.assert_("PART_NUMBER=ROCKET_LAUNCHER_0001" in h and
1145 "CUSTOMER=WILE_E_COYOTE" in h and
1146 "SHIPPING=FEDEX" not in h)
1147
1148 req = Request("http://www.acme.com/foo/")
1149 c.add_cookie_header(req)
1150
1151 h = req.get_header("Cookie")
1152 self.assert_(("PART_NUMBER=ROCKET_LAUNCHER_0001" in h and
1153 "CUSTOMER=WILE_E_COYOTE" in h and
1154 h.startswith("SHIPPING=FEDEX;")))
1155
1156 def test_netscape_example_2(self):
1157 from cookielib import CookieJar
1158 from urllib2 import Request
1159
1160 # Second Example transaction sequence:
1161 #
1162 # Assume all mappings from above have been cleared.
1163 #
1164 # Client receives:
1165 #
1166 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
1167 #
1168 # When client requests a URL in path "/" on this server, it sends:
1169 #
1170 # Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
1171 #
1172 # Client receives:
1173 #
1174 # Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
1175 #
1176 # When client requests a URL in path "/ammo" on this server, it sends:
1177 #
1178 # Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
1179 #
1180 # NOTE: There are two name/value pairs named "PART_NUMBER" due to
1181 # the inheritance of the "/" mapping in addition to the "/ammo" mapping.
1182
1183 c = CookieJar()
1184 headers = []
1185
1186 req = Request("http://www.acme.com/")
1187 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/")
1188 res = FakeResponse(headers, "http://www.acme.com/")
1189
1190 c.extract_cookies(res, req)
1191
1192 req = Request("http://www.acme.com/")
1193 c.add_cookie_header(req)
1194
1195 self.assertEquals(req.get_header("Cookie"),
1196 "PART_NUMBER=ROCKET_LAUNCHER_0001")
1197
1198 headers.append(
1199 "Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo")
1200 res = FakeResponse(headers, "http://www.acme.com/")
1201 c.extract_cookies(res, req)
1202
1203 req = Request("http://www.acme.com/ammo")
1204 c.add_cookie_header(req)
1205
1206 self.assert_(re.search(r"PART_NUMBER=RIDING_ROCKET_0023;\s*"
1207 "PART_NUMBER=ROCKET_LAUNCHER_0001",
1208 req.get_header("Cookie")))
1209
1210 def test_ietf_example_1(self):
1211 from cookielib import CookieJar, DefaultCookiePolicy
1212 #-------------------------------------------------------------------
1213 # Then we test with the examples from draft-ietf-http-state-man-mec-03.txt
1214 #
1215 # 5. EXAMPLES
1216
1217 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1218
1219 #
1220 # 5.1 Example 1
1221 #
1222 # Most detail of request and response headers has been omitted. Assume
1223 # the user agent has no stored cookies.
1224 #
1225 # 1. User Agent -> Server
1226 #
1227 # POST /acme/login HTTP/1.1
1228 # [form data]
1229 #
1230 # User identifies self via a form.
1231 #
1232 # 2. Server -> User Agent
1233 #
1234 # HTTP/1.1 200 OK
1235 # Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
1236 #
1237 # Cookie reflects user's identity.
1238
1239 cookie = interact_2965(
1240 c, 'http://www.acme.com/acme/login',
1241 'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"')
1242 self.assert_(not cookie)
1243
1244 #
1245 # 3. User Agent -> Server
1246 #
1247 # POST /acme/pickitem HTTP/1.1
1248 # Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
1249 # [form data]
1250 #
1251 # User selects an item for ``shopping basket.''
1252 #
1253 # 4. Server -> User Agent
1254 #
1255 # HTTP/1.1 200 OK
1256 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
1257 # Path="/acme"
1258 #
1259 # Shopping basket contains an item.
1260
1261 cookie = interact_2965(c, 'http://www.acme.com/acme/pickitem',
1262 'Part_Number="Rocket_Launcher_0001"; '
1263 'Version="1"; Path="/acme"');
1264 self.assert_(re.search(
1265 r'^\$Version="?1"?; Customer="?WILE_E_COYOTE"?; \$Path="/acme"$',
1266 cookie))
1267
1268 #
1269 # 5. User Agent -> Server
1270 #
1271 # POST /acme/shipping HTTP/1.1
1272 # Cookie: $Version="1";
1273 # Customer="WILE_E_COYOTE"; $Path="/acme";
1274 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1275 # [form data]
1276 #
1277 # User selects shipping method from form.
1278 #
1279 # 6. Server -> User Agent
1280 #
1281 # HTTP/1.1 200 OK
1282 # Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"
1283 #
1284 # New cookie reflects shipping method.
1285
1286 cookie = interact_2965(c, "http://www.acme.com/acme/shipping",
1287 'Shipping="FedEx"; Version="1"; Path="/acme"')
1288
1289 self.assert_(re.search(r'^\$Version="?1"?;', cookie))
1290 self.assert_(re.search(r'Part_Number="?Rocket_Launcher_0001"?;'
1291 '\s*\$Path="\/acme"', cookie))
1292 self.assert_(re.search(r'Customer="?WILE_E_COYOTE"?;\s*\$Path="\/acme"',
1293 cookie))
1294
1295 #
1296 # 7. User Agent -> Server
1297 #
1298 # POST /acme/process HTTP/1.1
1299 # Cookie: $Version="1";
1300 # Customer="WILE_E_COYOTE"; $Path="/acme";
1301 # Part_Number="Rocket_Launcher_0001"; $Path="/acme";
1302 # Shipping="FedEx"; $Path="/acme"
1303 # [form data]
1304 #
1305 # User chooses to process order.
1306 #
1307 # 8. Server -> User Agent
1308 #
1309 # HTTP/1.1 200 OK
1310 #
1311 # Transaction is complete.
1312
1313 cookie = interact_2965(c, "http://www.acme.com/acme/process")
1314 self.assert_(
1315 re.search(r'Shipping="?FedEx"?;\s*\$Path="\/acme"', cookie) and
1316 "WILE_E_COYOTE" in cookie)
1317
1318 #
1319 # The user agent makes a series of requests on the origin server, after
1320 # each of which it receives a new cookie. All the cookies have the same
1321 # Path attribute and (default) domain. Because the request URLs all have
1322 # /acme as a prefix, and that matches the Path attribute, each request
1323 # contains all the cookies received so far.
1324
1325 def test_ietf_example_2(self):
1326 from cookielib import CookieJar, DefaultCookiePolicy
1327
1328 # 5.2 Example 2
1329 #
1330 # This example illustrates the effect of the Path attribute. All detail
1331 # of request and response headers has been omitted. Assume the user agent
1332 # has no stored cookies.
1333
1334 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1335
1336 # Imagine the user agent has received, in response to earlier requests,
1337 # the response headers
1338 #
1339 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
1340 # Path="/acme"
1341 #
1342 # and
1343 #
1344 # Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1";
1345 # Path="/acme/ammo"
1346
1347 interact_2965(
1348 c, "http://www.acme.com/acme/ammo/specific",
1349 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"',
1350 'Part_Number="Riding_Rocket_0023"; Version="1"; Path="/acme/ammo"')
1351
1352 # A subsequent request by the user agent to the (same) server for URLs of
1353 # the form /acme/ammo/... would include the following request header:
1354 #
1355 # Cookie: $Version="1";
1356 # Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
1357 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1358 #
1359 # Note that the NAME=VALUE pair for the cookie with the more specific Path
1360 # attribute, /acme/ammo, comes before the one with the less specific Path
1361 # attribute, /acme. Further note that the same cookie name appears more
1362 # than once.
1363
1364 cookie = interact_2965(c, "http://www.acme.com/acme/ammo/...")
1365 self.assert_(
1366 re.search(r"Riding_Rocket_0023.*Rocket_Launcher_0001", cookie))
1367
1368 # A subsequent request by the user agent to the (same) server for a URL of
1369 # the form /acme/parts/ would include the following request header:
1370 #
1371 # Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1372 #
1373 # Here, the second cookie's Path attribute /acme/ammo is not a prefix of
1374 # the request URL, /acme/parts/, so the cookie does not get forwarded to
1375 # the server.
1376
1377 cookie = interact_2965(c, "http://www.acme.com/acme/parts/")
1378 self.assert_("Rocket_Launcher_0001" in cookie and
1379 "Riding_Rocket_0023" not in cookie)
1380
1381 def test_rejection(self):
1382 # Test rejection of Set-Cookie2 responses based on domain, path, port.
1383 from cookielib import DefaultCookiePolicy, LWPCookieJar
1384
1385 pol = DefaultCookiePolicy(rfc2965=True)
1386
1387 c = LWPCookieJar(policy=pol)
1388
1389 max_age = "max-age=3600"
1390
1391 # illegal domain (no embedded dots)
1392 cookie = interact_2965(c, "http://www.acme.com",
1393 'foo=bar; domain=".com"; version=1')
1394 self.assert_(not c)
1395
1396 # legal domain
1397 cookie = interact_2965(c, "http://www.acme.com",
1398 'ping=pong; domain="acme.com"; version=1')
1399 self.assertEquals(len(c), 1)
1400
1401 # illegal domain (host prefix "www.a" contains a dot)
1402 cookie = interact_2965(c, "http://www.a.acme.com",
1403 'whiz=bang; domain="acme.com"; version=1')
1404 self.assertEquals(len(c), 1)
1405
1406 # legal domain
1407 cookie = interact_2965(c, "http://www.a.acme.com",
1408 'wow=flutter; domain=".a.acme.com"; version=1')
1409 self.assertEquals(len(c), 2)
1410
1411 # can't partially match an IP-address
1412 cookie = interact_2965(c, "http://125.125.125.125",
1413 'zzzz=ping; domain="125.125.125"; version=1')
1414 self.assertEquals(len(c), 2)
1415
1416 # illegal path (must be prefix of request path)
1417 cookie = interact_2965(c, "http://www.sol.no",
1418 'blah=rhubarb; domain=".sol.no"; path="/foo"; '
1419 'version=1')
1420 self.assertEquals(len(c), 2)
1421
1422 # legal path
1423 cookie = interact_2965(c, "http://www.sol.no/foo/bar",
1424 'bing=bong; domain=".sol.no"; path="/foo"; '
1425 'version=1')
1426 self.assertEquals(len(c), 3)
1427
1428 # illegal port (request-port not in list)
1429 cookie = interact_2965(c, "http://www.sol.no",
1430 'whiz=ffft; domain=".sol.no"; port="90,100"; '
1431 'version=1')
1432 self.assertEquals(len(c), 3)
1433
1434 # legal port
1435 cookie = interact_2965(
1436 c, "http://www.sol.no",
1437 r'bang=wallop; version=1; domain=".sol.no"; '
1438 r'port="90,100, 80,8080"; '
1439 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "')
1440 self.assertEquals(len(c), 4)
1441
1442 # port attribute without any value (current port)
1443 cookie = interact_2965(c, "http://www.sol.no",
1444 'foo9=bar; version=1; domain=".sol.no"; port; '
1445 'max-age=100;')
1446 self.assertEquals(len(c), 5)
1447
1448 # encoded path
1449 # LWP has this test, but unescaping allowed path characters seems
1450 # like a bad idea, so I think this should fail:
1451## cookie = interact_2965(c, "http://www.sol.no/foo/",
1452## r'foo8=bar; version=1; path="/%66oo"')
1453 # but this is OK, because '<' is not an allowed HTTP URL path
1454 # character:
1455 cookie = interact_2965(c, "http://www.sol.no/<oo/",
1456 r'foo8=bar; version=1; path="/%3coo"')
1457 self.assertEquals(len(c), 6)
1458
1459 # save and restore
1460 filename = test_support.TESTFN
1461
1462 try:
1463 c.save(filename, ignore_discard=True)
1464 old = repr(c)
1465
1466 c = LWPCookieJar(policy=pol)
1467 c.load(filename, ignore_discard=True)
1468 finally:
1469 try: os.unlink(filename)
1470 except OSError: pass
1471
1472 self.assertEquals(old, repr(c))
1473
1474 def test_url_encoding(self):
1475 # Try some URL encodings of the PATHs.
1476 # (the behaviour here has changed from libwww-perl)
1477 from cookielib import CookieJar, DefaultCookiePolicy
1478
1479 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1480 interact_2965(c, "http://www.acme.com/foo%2f%25/%3c%3c%0Anew%E5/%E5",
1481 "foo = bar; version = 1")
1482
1483 cookie = interact_2965(
1484 c, "http://www.acme.com/foo%2f%25/<<%0anewå/æøå",
1485 'bar=baz; path="/foo/"; version=1');
1486 version_re = re.compile(r'^\$version=\"?1\"?', re.I)
1487 self.assert_("foo=bar" in cookie and version_re.search(cookie))
1488
1489 cookie = interact_2965(
1490 c, "http://www.acme.com/foo/%25/<<%0anewå/æøå")
1491 self.assert_(not cookie)
1492
1493 # unicode URL doesn't raise exception
1494 cookie = interact_2965(c, u"http://www.acme.com/\xfc")
1495
1496 def test_mozilla(self):
1497 # Save / load Mozilla/Netscape cookie file format.
1498 from cookielib import MozillaCookieJar, DefaultCookiePolicy
1499
1500 year_plus_one = time.localtime()[0] + 1
1501
1502 filename = test_support.TESTFN
1503
1504 c = MozillaCookieJar(filename,
1505 policy=DefaultCookiePolicy(rfc2965=True))
1506 interact_2965(c, "http://www.acme.com/",
1507 "foo1=bar; max-age=100; Version=1")
1508 interact_2965(c, "http://www.acme.com/",
1509 'foo2=bar; port="80"; max-age=100; Discard; Version=1')
1510 interact_2965(c, "http://www.acme.com/", "foo3=bar; secure; Version=1")
1511
1512 expires = "expires=09-Nov-%d 23:12:40 GMT" % (year_plus_one,)
1513 interact_netscape(c, "http://www.foo.com/",
1514 "fooa=bar; %s" % expires)
1515 interact_netscape(c, "http://www.foo.com/",
1516 "foob=bar; Domain=.foo.com; %s" % expires)
1517 interact_netscape(c, "http://www.foo.com/",
1518 "fooc=bar; Domain=www.foo.com; %s" % expires)
1519
1520 def save_and_restore(cj, ignore_discard):
1521 try:
1522 cj.save(ignore_discard=ignore_discard)
1523 new_c = MozillaCookieJar(filename,
1524 DefaultCookiePolicy(rfc2965=True))
1525 new_c.load(ignore_discard=ignore_discard)
1526 finally:
1527 try: os.unlink(filename)
1528 except OSError: pass
1529 return new_c
1530
1531 new_c = save_and_restore(c, True)
1532 self.assertEquals(len(new_c), 6) # none discarded
1533 self.assert_("name='foo1', value='bar'" in repr(new_c))
1534
1535 new_c = save_and_restore(c, False)
1536 self.assertEquals(len(new_c), 4) # 2 of them discarded on save
1537 self.assert_("name='foo1', value='bar'" in repr(new_c))
1538
1539 def test_netscape_misc(self):
1540 # Some additional Netscape cookies tests.
1541 from cookielib import CookieJar
1542 from urllib2 import Request
1543
1544 c = CookieJar()
1545 headers = []
1546 req = Request("http://foo.bar.acme.com/foo")
1547
1548 # Netscape allows a host part that contains dots
1549 headers.append("Set-Cookie: Customer=WILE_E_COYOTE; domain=.acme.com")
1550 res = FakeResponse(headers, "http://www.acme.com/foo")
1551 c.extract_cookies(res, req)
1552
1553 # and that the domain is the same as the host without adding a leading
1554 # dot to the domain. Should not quote even if strange chars are used
1555 # in the cookie value.
1556 headers.append("Set-Cookie: PART_NUMBER=3,4; domain=foo.bar.acme.com")
1557 res = FakeResponse(headers, "http://www.acme.com/foo")
1558 c.extract_cookies(res, req)
1559
1560 req = Request("http://foo.bar.acme.com/foo")
1561 c.add_cookie_header(req)
1562 self.assert_(
1563 "PART_NUMBER=3,4" in req.get_header("Cookie") and
1564 "Customer=WILE_E_COYOTE" in req.get_header("Cookie"))
1565
1566 def test_intranet_domains_2965(self):
1567 # Test handling of local intranet hostnames without a dot.
1568 from cookielib import CookieJar, DefaultCookiePolicy
1569
1570 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1571 interact_2965(c, "http://example/",
1572 "foo1=bar; PORT; Discard; Version=1;")
1573 cookie = interact_2965(c, "http://example/",
1574 'foo2=bar; domain=".local"; Version=1')
1575 self.assert_("foo1=bar" in cookie)
1576
1577 interact_2965(c, "http://example/", 'foo3=bar; Version=1')
1578 cookie = interact_2965(c, "http://example/")
1579 self.assert_("foo2=bar" in cookie and len(c) == 3)
1580
1581 def test_intranet_domains_ns(self):
1582 from cookielib import CookieJar, DefaultCookiePolicy
1583
1584 c = CookieJar(DefaultCookiePolicy(rfc2965 = False))
1585 interact_netscape(c, "http://example/", "foo1=bar")
1586 cookie = interact_netscape(c, "http://example/",
1587 'foo2=bar; domain=.local')
1588 self.assertEquals(len(c), 2)
1589 self.assert_("foo1=bar" in cookie)
1590
1591 cookie = interact_netscape(c, "http://example/")
1592 self.assert_("foo2=bar" in cookie)
1593 self.assertEquals(len(c), 2)
1594
1595 def test_empty_path(self):
1596 from cookielib import CookieJar, DefaultCookiePolicy
1597 from urllib2 import Request
1598
1599 # Test for empty path
1600 # Broken web-server ORION/1.3.38 returns to the client response like
1601 #
1602 # Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=
1603 #
1604 # ie. with Path set to nothing.
1605 # In this case, extract_cookies() must set cookie to / (root)
1606 c = CookieJar(DefaultCookiePolicy(rfc2965 = True))
1607 headers = []
1608
1609 req = Request("http://www.ants.com/")
1610 headers.append("Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=")
1611 res = FakeResponse(headers, "http://www.ants.com/")
1612 c.extract_cookies(res, req)
1613
1614 req = Request("http://www.ants.com/")
1615 c.add_cookie_header(req)
1616
1617 self.assertEquals(req.get_header("Cookie"),
1618 "JSESSIONID=ABCDERANDOM123")
1619 self.assertEquals(req.get_header("Cookie2"), '$Version="1"')
1620
1621 # missing path in the request URI
1622 req = Request("http://www.ants.com:8080")
1623 c.add_cookie_header(req)
1624
1625 self.assertEquals(req.get_header("Cookie"),
1626 "JSESSIONID=ABCDERANDOM123")
1627 self.assertEquals(req.get_header("Cookie2"), '$Version="1"')
1628
1629 def test_session_cookies(self):
1630 from cookielib import CookieJar
1631 from urllib2 import Request
1632
1633 year_plus_one = time.localtime()[0] + 1
1634
1635 # Check session cookies are deleted properly by
1636 # CookieJar.clear_session_cookies method
1637
1638 req = Request('http://www.perlmeister.com/scripts')
1639 headers = []
1640 headers.append("Set-Cookie: s1=session;Path=/scripts")
1641 headers.append("Set-Cookie: p1=perm; Domain=.perlmeister.com;"
1642 "Path=/;expires=Fri, 02-Feb-%d 23:24:20 GMT" %
1643 year_plus_one)
1644 headers.append("Set-Cookie: p2=perm;Path=/;expires=Fri, "
1645 "02-Feb-%d 23:24:20 GMT" % year_plus_one)
1646 headers.append("Set-Cookie: s2=session;Path=/scripts;"
1647 "Domain=.perlmeister.com")
1648 headers.append('Set-Cookie2: s3=session;Version=1;Discard;Path="/"')
1649 res = FakeResponse(headers, 'http://www.perlmeister.com/scripts')
1650
1651 c = CookieJar()
1652 c.extract_cookies(res, req)
1653 # How many session/permanent cookies do we have?
1654 counter = {"session_after": 0,
1655 "perm_after": 0,
1656 "session_before": 0,
1657 "perm_before": 0}
1658 for cookie in c:
1659 key = "%s_before" % cookie.value
1660 counter[key] = counter[key] + 1
1661 c.clear_session_cookies()
1662 # How many now?
1663 for cookie in c:
1664 key = "%s_after" % cookie.value
1665 counter[key] = counter[key] + 1
1666
1667 self.assert_(not (
1668 # a permanent cookie got lost accidently
1669 counter["perm_after"] != counter["perm_before"] or
1670 # a session cookie hasn't been cleared
1671 counter["session_after"] != 0 or
1672 # we didn't have session cookies in the first place
1673 counter["session_before"] == 0))
1674
1675
1676def test_main(verbose=None):
1677 from test import test_sets
1678 test_support.run_unittest(
1679 DateTimeTests,
1680 HeaderTests,
1681 CookieTests,
Martin v. Löwisc5574e82005-03-03 10:57:37 +00001682 FileCookieJarTests,
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001683 LWPCookieTests,
1684 )
1685
1686if __name__ == "__main__":
1687 test_main(verbose=True)