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