blob: ea3c827fb7e32e366e06ed2fb9996d7e7d416622 [file] [log] [blame]
Georg Brandl24420152008-05-26 16:32:26 +00001"""Tests for http/cookiejar.py."""
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00002
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +00003import os
4import re
5import test.support
6import time
7import unittest
8import urllib.request
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00009
Ezio Melotti1d237e52013-08-10 18:20:09 +030010from http.cookiejar import (time2isoz, http2time, iso2time, time2netscape,
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +000011 parse_ns_headers, join_header_words, split_header_words, Cookie,
12 CookieJar, DefaultCookiePolicy, LWPCookieJar, MozillaCookieJar,
13 LoadError, lwp_cookie_str, DEFAULT_HTTP_PORT, escape_path,
14 reach, is_HDN, domain_match, user_domain_match, request_path,
15 request_port, request_host)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000016
Georg Brandl24420152008-05-26 16:32:26 +000017
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +000018class DateTimeTests(unittest.TestCase):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000019
20 def test_time2isoz(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000021 base = 1019227000
22 day = 24*3600
Ezio Melottib3aedd42010-11-20 19:04:17 +000023 self.assertEqual(time2isoz(base), "2002-04-19 14:36:40Z")
24 self.assertEqual(time2isoz(base+day), "2002-04-20 14:36:40Z")
25 self.assertEqual(time2isoz(base+2*day), "2002-04-21 14:36:40Z")
26 self.assertEqual(time2isoz(base+3*day), "2002-04-22 14:36:40Z")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000027
28 az = time2isoz()
29 bz = time2isoz(500000)
30 for text in (az, bz):
Serhiy Storchaka9d282f62013-11-17 13:45:02 +020031 self.assertRegex(text, r"^\d{4}-\d\d-\d\d \d\d:\d\d:\d\dZ$",
32 "bad time2isoz format: %s %s" % (az, bz))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000033
34 def test_http2time(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000035 def parse_date(text):
36 return time.gmtime(http2time(text))[:6]
37
Ezio Melottib3aedd42010-11-20 19:04:17 +000038 self.assertEqual(parse_date("01 Jan 2001"), (2001, 1, 1, 0, 0, 0.0))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000039
40 # this test will break around year 2070
Ezio Melottib3aedd42010-11-20 19:04:17 +000041 self.assertEqual(parse_date("03-Feb-20"), (2020, 2, 3, 0, 0, 0.0))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000042
43 # this test will break around year 2048
Ezio Melottib3aedd42010-11-20 19:04:17 +000044 self.assertEqual(parse_date("03-Feb-98"), (1998, 2, 3, 0, 0, 0.0))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000045
46 def test_http2time_formats(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000047 # test http2time for supported dates. Test cases with 2 digit year
48 # will probably break in year 2044.
49 tests = [
50 'Thu, 03 Feb 1994 00:00:00 GMT', # proposed new HTTP format
51 'Thursday, 03-Feb-94 00:00:00 GMT', # old rfc850 HTTP format
52 'Thursday, 03-Feb-1994 00:00:00 GMT', # broken rfc850 HTTP format
53
54 '03 Feb 1994 00:00:00 GMT', # HTTP format (no weekday)
55 '03-Feb-94 00:00:00 GMT', # old rfc850 (no weekday)
56 '03-Feb-1994 00:00:00 GMT', # broken rfc850 (no weekday)
57 '03-Feb-1994 00:00 GMT', # broken rfc850 (no weekday, no seconds)
58 '03-Feb-1994 00:00', # broken rfc850 (no weekday, no seconds, no tz)
Ezio Melotti7ac17f82013-08-10 18:07:25 +030059 '02-Feb-1994 24:00', # broken rfc850 (no weekday, no seconds,
60 # no tz) using hour 24 with yesterday date
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000061
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"
Ezio Melottib3aedd42010-11-20 19:04:17 +000074 self.assertEqual(result, expected,
75 "%s => '%s' (%s)" % (test_t, result, expected))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000076
77 for s in tests:
Serhiy Storchaka9d282f62013-11-17 13:45:02 +020078 self.assertEqual(http2time(s), test_t, s)
79 self.assertEqual(http2time(s.lower()), test_t, s.lower())
80 self.assertEqual(http2time(s.upper()), test_t, s.upper())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000081
82 def test_http2time_garbage(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000083 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',
Berker Peksag20be53e2016-03-14 05:48:02 +020094 '08-Oct-3697739',
95 '08-01-3697739',
96 '09 Feb 19942632 22:23:32 GMT',
97 'Wed, 09 Feb 1994834 22:23:32 GMT',
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000098 ]:
Ezio Melotti1d237e52013-08-10 18:20:09 +030099 self.assertIsNone(http2time(test),
100 "http2time(%s) is not None\n"
101 "http2time(test) %s" % (test, http2time(test)))
102
103 def test_iso2time(self):
104 def parse_date(text):
105 return time.gmtime(iso2time(text))[:6]
106
107 # ISO 8601 compact format
108 self.assertEqual(parse_date("19940203T141529Z"),
109 (1994, 2, 3, 14, 15, 29))
110
111 # ISO 8601 with time behind UTC
112 self.assertEqual(parse_date("1994-02-03 07:15:29 -0700"),
113 (1994, 2, 3, 14, 15, 29))
114
115 # ISO 8601 with time ahead of UTC
116 self.assertEqual(parse_date("1994-02-03 19:45:29 +0530"),
117 (1994, 2, 3, 14, 15, 29))
118
119 def test_iso2time_formats(self):
120 # test iso2time for supported dates.
121 tests = [
122 '1994-02-03 00:00:00 -0000', # ISO 8601 format
123 '1994-02-03 00:00:00 +0000', # ISO 8601 format
124 '1994-02-03 00:00:00', # zone is optional
125 '1994-02-03', # only date
126 '1994-02-03T00:00:00', # Use T as separator
127 '19940203', # only date
128 '1994-02-02 24:00:00', # using hour-24 yesterday date
129 '19940203T000000Z', # ISO 8601 compact format
130
131 # A few tests with extra space at various places
132 ' 1994-02-03 ',
133 ' 1994-02-03T00:00:00 ',
134 ]
135
136 test_t = 760233600 # assume broken POSIX counting of seconds
137 for s in tests:
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200138 self.assertEqual(iso2time(s), test_t, s)
139 self.assertEqual(iso2time(s.lower()), test_t, s.lower())
140 self.assertEqual(iso2time(s.upper()), test_t, s.upper())
Ezio Melotti1d237e52013-08-10 18:20:09 +0300141
142 def test_iso2time_garbage(self):
143 for test in [
144 '',
145 'Garbage',
146 'Thursday, 03-Feb-94 00:00:00 GMT',
147 '1980-00-01',
148 '1980-13-01',
149 '1980-01-00',
150 '1980-01-32',
151 '1980-01-01 25:00:00',
152 '1980-01-01 00:61:00',
153 '01-01-1980 00:00:62',
154 '01-01-1980T00:00:62',
155 '19800101T250000Z'
156 '1980-01-01 00:00:00 -2500',
157 ]:
158 self.assertIsNone(iso2time(test),
159 "iso2time(%s) is not None\n"
160 "iso2time(test) %s" % (test, iso2time(test)))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000161
162
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000163class HeaderTests(unittest.TestCase):
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000164
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000165 def test_parse_ns_headers(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000166 # quotes should be stripped
Guido van Rossume2a383d2007-01-15 16:59:06 +0000167 expected = [[('foo', 'bar'), ('expires', 2209069412), ('version', '0')]]
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000168 for hdr in [
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000169 'foo=bar; expires=01 Jan 2040 22:23:32 GMT',
170 'foo=bar; expires="01 Jan 2040 22:23:32 GMT"',
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000171 ]:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000172 self.assertEqual(parse_ns_headers([hdr]), expected)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000173
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000174 def test_parse_ns_headers_version(self):
175
176 # quotes should be stripped
177 expected = [[('foo', 'bar'), ('version', '1')]]
178 for hdr in [
179 'foo=bar; version="1"',
180 'foo=bar; Version="1"',
181 ]:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000182 self.assertEqual(parse_ns_headers([hdr]), expected)
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000183
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000184 def test_parse_ns_headers_special_names(self):
185 # names such as 'expires' are not special in first name=value pair
186 # of Set-Cookie: header
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000187 # Cookie with name 'expires'
188 hdr = 'expires=01 Jan 2040 22:23:32 GMT'
189 expected = [[("expires", "01 Jan 2040 22:23:32 GMT"), ("version", "0")]]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000190 self.assertEqual(parse_ns_headers([hdr]), expected)
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000191
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000192 def test_join_header_words(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000193 joined = join_header_words([[("foo", None), ("bar", "baz")]])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000194 self.assertEqual(joined, "foo; bar=baz")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000195
Ezio Melottib3aedd42010-11-20 19:04:17 +0000196 self.assertEqual(join_header_words([[]]), "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000197
198 def test_split_header_words(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000199 tests = [
200 ("foo", [[("foo", None)]]),
201 ("foo=bar", [[("foo", "bar")]]),
202 (" foo ", [[("foo", None)]]),
203 (" foo= ", [[("foo", "")]]),
204 (" foo=", [[("foo", "")]]),
205 (" foo= ; ", [[("foo", "")]]),
206 (" foo= ; bar= baz ", [[("foo", ""), ("bar", "baz")]]),
207 ("foo=bar bar=baz", [[("foo", "bar"), ("bar", "baz")]]),
208 # doesn't really matter if this next fails, but it works ATM
209 ("foo= bar=baz", [[("foo", "bar=baz")]]),
210 ("foo=bar;bar=baz", [[("foo", "bar"), ("bar", "baz")]]),
211 ('foo bar baz', [[("foo", None), ("bar", None), ("baz", None)]]),
212 ("a, b, c", [[("a", None)], [("b", None)], [("c", None)]]),
213 (r'foo; bar=baz, spam=, foo="\,\;\"", bar= ',
214 [[("foo", None), ("bar", "baz")],
215 [("spam", "")], [("foo", ',;"')], [("bar", "")]]),
216 ]
217
218 for arg, expect in tests:
219 try:
220 result = split_header_words([arg])
221 except:
Guido van Rossum34d19282007-08-09 01:03:29 +0000222 import traceback, io
223 f = io.StringIO()
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000224 traceback.print_exc(None, f)
225 result = "(error -- traceback follows)\n\n%s" % f.getvalue()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000226 self.assertEqual(result, expect, """
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000227When parsing: '%s'
228Expected: '%s'
229Got: '%s'
230""" % (arg, expect, result))
231
232 def test_roundtrip(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000233 tests = [
234 ("foo", "foo"),
235 ("foo=bar", "foo=bar"),
236 (" foo ", "foo"),
237 ("foo=", 'foo=""'),
238 ("foo=bar bar=baz", "foo=bar; bar=baz"),
239 ("foo=bar;bar=baz", "foo=bar; bar=baz"),
240 ('foo bar baz', "foo; bar; baz"),
241 (r'foo="\"" bar="\\"', r'foo="\""; bar="\\"'),
242 ('foo,,,bar', 'foo, bar'),
243 ('foo=bar,bar=baz', 'foo=bar, bar=baz'),
244
245 ('text/html; charset=iso-8859-1',
246 'text/html; charset="iso-8859-1"'),
247
248 ('foo="bar"; port="80,81"; discard, bar=baz',
249 'foo=bar; port="80,81"; discard, bar=baz'),
250
251 (r'Basic realm="\"foo\\\\bar\""',
252 r'Basic; realm="\"foo\\\\bar\""')
253 ]
254
255 for arg, expect in tests:
256 input = split_header_words([arg])
257 res = join_header_words(input)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000258 self.assertEqual(res, expect, """
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000259When parsing: '%s'
260Expected: '%s'
261Got: '%s'
262Input was: '%s'
263""" % (arg, expect, res, input))
264
265
266class FakeResponse:
267 def __init__(self, headers=[], url=None):
268 """
269 headers: list of RFC822-style 'Key: value' strings
270 """
Barry Warsaw820c1202008-06-12 04:06:45 +0000271 import email
272 self._headers = email.message_from_string("\n".join(headers))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000273 self._url = url
274 def info(self): return self._headers
275
276def interact_2965(cookiejar, url, *set_cookie_hdrs):
277 return _interact(cookiejar, url, set_cookie_hdrs, "Set-Cookie2")
278
279def interact_netscape(cookiejar, url, *set_cookie_hdrs):
280 return _interact(cookiejar, url, set_cookie_hdrs, "Set-Cookie")
281
282def _interact(cookiejar, url, set_cookie_hdrs, hdr_name):
283 """Perform a single request / response cycle, returning Cookie: header."""
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000284 req = urllib.request.Request(url)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000285 cookiejar.add_cookie_header(req)
286 cookie_hdr = req.get_header("Cookie", "")
287 headers = []
288 for hdr in set_cookie_hdrs:
289 headers.append("%s: %s" % (hdr_name, hdr))
290 res = FakeResponse(headers, url)
291 cookiejar.extract_cookies(res, req)
292 return cookie_hdr
293
294
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000295class FileCookieJarTests(unittest.TestCase):
Martin v. Löwisc5574e82005-03-03 10:57:37 +0000296 def test_lwp_valueless_cookie(self):
297 # cookies with no value should be saved and loaded consistently
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000298 filename = test.support.TESTFN
Martin v. Löwisc5574e82005-03-03 10:57:37 +0000299 c = LWPCookieJar()
300 interact_netscape(c, "http://www.acme.com/", 'boo')
301 self.assertEqual(c._cookies["www.acme.com"]["/"]["boo"].value, None)
302 try:
303 c.save(filename, ignore_discard=True)
304 c = LWPCookieJar()
305 c.load(filename, ignore_discard=True)
306 finally:
307 try: os.unlink(filename)
308 except OSError: pass
309 self.assertEqual(c._cookies["www.acme.com"]["/"]["boo"].value, None)
310
Neal Norwitz3e7de592005-12-23 21:24:35 +0000311 def test_bad_magic(self):
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200312 # OSErrors (eg. file doesn't exist) are allowed to propagate
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000313 filename = test.support.TESTFN
Neal Norwitz3e7de592005-12-23 21:24:35 +0000314 for cookiejar_class in LWPCookieJar, MozillaCookieJar:
315 c = cookiejar_class()
316 try:
317 c.load(filename="for this test to work, a file with this "
318 "filename should not exist")
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200319 except OSError as exc:
320 # an OSError subclass (likely FileNotFoundError), but not
321 # LoadError
322 self.assertIsNot(exc.__class__, LoadError)
Neal Norwitz3e7de592005-12-23 21:24:35 +0000323 else:
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200324 self.fail("expected OSError for invalid filename")
Neal Norwitz3e7de592005-12-23 21:24:35 +0000325 # Invalid contents of cookies file (eg. bad magic string)
326 # causes a LoadError.
327 try:
Brett Cannon7f462fc2010-10-29 23:27:39 +0000328 with open(filename, "w") as f:
329 f.write("oops\n")
330 for cookiejar_class in LWPCookieJar, MozillaCookieJar:
331 c = cookiejar_class()
332 self.assertRaises(LoadError, c.load, filename)
Neal Norwitz3e7de592005-12-23 21:24:35 +0000333 finally:
334 try: os.unlink(filename)
335 except OSError: pass
Martin v. Löwisc5574e82005-03-03 10:57:37 +0000336
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000337class CookieTests(unittest.TestCase):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000338 # XXX
339 # Get rid of string comparisons where not actually testing str / repr.
340 # .clear() etc.
341 # IP addresses like 50 (single number, no dot) and domain-matching
342 # functions (and is_HDN)? See draft RFC 2965 errata.
343 # Strictness switches
344 # is_third_party()
345 # unverifiability / third-party blocking
346 # Netscape cookies work the same as RFC 2965 with regard to port.
347 # Set-Cookie with negative max age.
348 # If turn RFC 2965 handling off, Set-Cookie2 cookies should not clobber
349 # Set-Cookie cookies.
350 # Cookie2 should be sent if *any* cookies are not V1 (ie. V0 OR V2 etc.).
351 # Cookies (V1 and V0) with no expiry date should be set to be discarded.
352 # RFC 2965 Quoting:
353 # Should accept unquoted cookie-attribute values? check errata draft.
354 # Which are required on the way in and out?
355 # Should always return quoted cookie-attribute values?
356 # Proper testing of when RFC 2965 clobbers Netscape (waiting for errata).
357 # Path-match on return (same for V0 and V1).
358 # RFC 2965 acceptance and returning rules
359 # Set-Cookie2 without version attribute is rejected.
360
361 # Netscape peculiarities list from Ronald Tschalar.
362 # The first two still need tests, the rest are covered.
363## - Quoting: only quotes around the expires value are recognized as such
364## (and yes, some folks quote the expires value); quotes around any other
365## value are treated as part of the value.
366## - White space: white space around names and values is ignored
367## - Default path: if no path parameter is given, the path defaults to the
368## path in the request-uri up to, but not including, the last '/'. Note
369## that this is entirely different from what the spec says.
370## - Commas and other delimiters: Netscape just parses until the next ';'.
371## This means it will allow commas etc inside values (and yes, both
372## commas and equals are commonly appear in the cookie value). This also
373## means that if you fold multiple Set-Cookie header fields into one,
374## comma-separated list, it'll be a headache to parse (at least my head
Ezio Melotti85a86292013-08-17 16:57:41 +0300375## starts hurting every time I think of that code).
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000376## - Expires: You'll get all sorts of date formats in the expires,
377## including emtpy expires attributes ("expires="). Be as flexible as you
378## can, and certainly don't expect the weekday to be there; if you can't
379## parse it, just ignore it and pretend it's a session cookie.
380## - Domain-matching: Netscape uses the 2-dot rule for _all_ domains, not
381## just the 7 special TLD's listed in their spec. And folks rely on
382## that...
383
384 def test_domain_return_ok(self):
385 # test optimization: .domain_return_ok() should filter out most
386 # domains in the CookieJar before we try to access them (because that
387 # may require disk access -- in particular, with MSIECookieJar)
388 # This is only a rough check for performance reasons, so it's not too
389 # critical as long as it's sufficiently liberal.
Georg Brandl24420152008-05-26 16:32:26 +0000390 pol = DefaultCookiePolicy()
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000391 for url, domain, ok in [
392 ("http://foo.bar.com/", "blah.com", False),
393 ("http://foo.bar.com/", "rhubarb.blah.com", False),
394 ("http://foo.bar.com/", "rhubarb.foo.bar.com", False),
395 ("http://foo.bar.com/", ".foo.bar.com", True),
396 ("http://foo.bar.com/", "foo.bar.com", True),
397 ("http://foo.bar.com/", ".bar.com", True),
398 ("http://foo.bar.com/", "com", True),
399 ("http://foo.com/", "rhubarb.foo.com", False),
400 ("http://foo.com/", ".foo.com", True),
401 ("http://foo.com/", "foo.com", True),
402 ("http://foo.com/", "com", True),
403 ("http://foo/", "rhubarb.foo", False),
404 ("http://foo/", ".foo", True),
405 ("http://foo/", "foo", True),
406 ("http://foo/", "foo.local", True),
407 ("http://foo/", ".local", True),
408 ]:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000409 request = urllib.request.Request(url)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000410 r = pol.domain_return_ok(domain, request)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000411 if ok: self.assertTrue(r)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200412 else: self.assertFalse(r)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000413
414 def test_missing_value(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000415 # missing = sign in Cookie: header is regarded by Mozilla as a missing
Georg Brandl24420152008-05-26 16:32:26 +0000416 # name, and by http.cookiejar as a missing value
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000417 filename = test.support.TESTFN
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000418 c = MozillaCookieJar(filename)
419 interact_netscape(c, "http://www.acme.com/", 'eggs')
420 interact_netscape(c, "http://www.acme.com/", '"spam"; path=/foo/')
421 cookie = c._cookies["www.acme.com"]["/"]["eggs"]
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200422 self.assertIsNone(cookie.value)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000423 self.assertEqual(cookie.name, "eggs")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000424 cookie = c._cookies["www.acme.com"]['/foo/']['"spam"']
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200425 self.assertIsNone(cookie.value)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000426 self.assertEqual(cookie.name, '"spam"')
427 self.assertEqual(lwp_cookie_str(cookie), (
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000428 r'"spam"; path="/foo/"; domain="www.acme.com"; '
429 'path_spec; discard; version=0'))
430 old_str = repr(c)
431 c.save(ignore_expires=True, ignore_discard=True)
432 try:
433 c = MozillaCookieJar(filename)
434 c.revert(ignore_expires=True, ignore_discard=True)
435 finally:
436 os.unlink(c.filename)
437 # cookies unchanged apart from lost info re. whether path was specified
Ezio Melottib3aedd42010-11-20 19:04:17 +0000438 self.assertEqual(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000439 repr(c),
440 re.sub("path_specified=%s" % True, "path_specified=%s" % False,
441 old_str)
442 )
Ezio Melottib3aedd42010-11-20 19:04:17 +0000443 self.assertEqual(interact_netscape(c, "http://www.acme.com/foo/"),
444 '"spam"; eggs')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000445
Neal Norwitz71dad722005-12-23 21:43:48 +0000446 def test_rfc2109_handling(self):
447 # RFC 2109 cookies are handled as RFC 2965 or Netscape cookies,
448 # dependent on policy settings
Neal Norwitz71dad722005-12-23 21:43:48 +0000449 for rfc2109_as_netscape, rfc2965, version in [
450 # default according to rfc2965 if not explicitly specified
451 (None, False, 0),
452 (None, True, 1),
453 # explicit rfc2109_as_netscape
454 (False, False, None), # version None here means no cookie stored
455 (False, True, 1),
456 (True, False, 0),
457 (True, True, 0),
458 ]:
459 policy = DefaultCookiePolicy(
460 rfc2109_as_netscape=rfc2109_as_netscape,
461 rfc2965=rfc2965)
462 c = CookieJar(policy)
463 interact_netscape(c, "http://www.example.com/", "ni=ni; Version=1")
464 try:
465 cookie = c._cookies["www.example.com"]["/"]["ni"]
466 except KeyError:
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200467 self.assertIsNone(version) # didn't expect a stored cookie
Neal Norwitz71dad722005-12-23 21:43:48 +0000468 else:
469 self.assertEqual(cookie.version, version)
470 # 2965 cookies are unaffected
471 interact_2965(c, "http://www.example.com/",
472 "foo=bar; Version=1")
473 if rfc2965:
474 cookie2965 = c._cookies["www.example.com"]["/"]["foo"]
475 self.assertEqual(cookie2965.version, 1)
476
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000477 def test_ns_parser(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000478 c = CookieJar()
479 interact_netscape(c, "http://www.acme.com/",
480 'spam=eggs; DoMain=.acme.com; port; blArgh="feep"')
481 interact_netscape(c, "http://www.acme.com/", 'ni=ni; port=80,8080')
482 interact_netscape(c, "http://www.acme.com:80/", 'nini=ni')
483 interact_netscape(c, "http://www.acme.com:80/", 'foo=bar; expires=')
484 interact_netscape(c, "http://www.acme.com:80/", 'spam=eggs; '
485 'expires="Foo Bar 25 33:22:11 3022"')
Serhiy Storchaka577fc4e2015-03-13 09:05:01 +0200486 interact_netscape(c, 'http://www.acme.com/', 'fortytwo=')
487 interact_netscape(c, 'http://www.acme.com/', '=unladenswallow')
488 interact_netscape(c, 'http://www.acme.com/', 'holyhandgrenade')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000489
490 cookie = c._cookies[".acme.com"]["/"]["spam"]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000491 self.assertEqual(cookie.domain, ".acme.com")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000492 self.assertTrue(cookie.domain_specified)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000493 self.assertEqual(cookie.port, DEFAULT_HTTP_PORT)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200494 self.assertFalse(cookie.port_specified)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000495 # case is preserved
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200496 self.assertTrue(cookie.has_nonstandard_attr("blArgh"))
497 self.assertFalse(cookie.has_nonstandard_attr("blargh"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000498
499 cookie = c._cookies["www.acme.com"]["/"]["ni"]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000500 self.assertEqual(cookie.domain, "www.acme.com")
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200501 self.assertFalse(cookie.domain_specified)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000502 self.assertEqual(cookie.port, "80,8080")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000503 self.assertTrue(cookie.port_specified)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000504
505 cookie = c._cookies["www.acme.com"]["/"]["nini"]
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200506 self.assertIsNone(cookie.port)
507 self.assertFalse(cookie.port_specified)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000508
509 # invalid expires should not cause cookie to be dropped
510 foo = c._cookies["www.acme.com"]["/"]["foo"]
511 spam = c._cookies["www.acme.com"]["/"]["foo"]
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200512 self.assertIsNone(foo.expires)
513 self.assertIsNone(spam.expires)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000514
Serhiy Storchaka577fc4e2015-03-13 09:05:01 +0200515 cookie = c._cookies['www.acme.com']['/']['fortytwo']
516 self.assertIsNotNone(cookie.value)
517 self.assertEqual(cookie.value, '')
518
519 # there should be a distinction between a present but empty value
520 # (above) and a value that's entirely missing (below)
521
522 cookie = c._cookies['www.acme.com']['/']['holyhandgrenade']
523 self.assertIsNone(cookie.value)
524
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000525 def test_ns_parser_special_names(self):
526 # names such as 'expires' are not special in first name=value pair
527 # of Set-Cookie: header
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000528 c = CookieJar()
529 interact_netscape(c, "http://www.acme.com/", 'expires=eggs')
530 interact_netscape(c, "http://www.acme.com/", 'version=eggs; spam=eggs')
531
532 cookies = c._cookies["www.acme.com"]["/"]
Benjamin Peterson577473f2010-01-19 00:09:57 +0000533 self.assertIn('expires', cookies)
534 self.assertIn('version', cookies)
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000535
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000536 def test_expires(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000537 # if expires is in future, keep cookie...
538 c = CookieJar()
539 future = time2netscape(time.time()+3600)
540 interact_netscape(c, "http://www.acme.com/", 'spam="bar"; expires=%s' %
541 future)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000542 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000543 now = time2netscape(time.time()-1)
544 # ... and if in past or present, discard it
545 interact_netscape(c, "http://www.acme.com/", 'foo="eggs"; expires=%s' %
546 now)
547 h = interact_netscape(c, "http://www.acme.com/")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000548 self.assertEqual(len(c), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000549 self.assertIn('spam="bar"', h)
550 self.assertNotIn("foo", h)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000551
552 # max-age takes precedence over expires, and zero max-age is request to
553 # delete both new cookie and any old matching cookie
554 interact_netscape(c, "http://www.acme.com/", 'eggs="bar"; expires=%s' %
555 future)
556 interact_netscape(c, "http://www.acme.com/", 'bar="bar"; expires=%s' %
557 future)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000558 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000559 interact_netscape(c, "http://www.acme.com/", 'eggs="bar"; '
560 'expires=%s; max-age=0' % future)
561 interact_netscape(c, "http://www.acme.com/", 'bar="bar"; '
562 'max-age=0; expires=%s' % future)
563 h = interact_netscape(c, "http://www.acme.com/")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000564 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000565
566 # test expiry at end of session for cookies with no expires attribute
567 interact_netscape(c, "http://www.rhubarb.net/", 'whum="fizz"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000568 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000569 c.clear_session_cookies()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000570 self.assertEqual(len(c), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000571 self.assertIn('spam="bar"', h)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000572
Robert Collinsa0e5d982015-08-04 10:06:29 +1200573 # test if fractional expiry is accepted
574 cookie = Cookie(0, "name", "value",
575 None, False, "www.python.org",
576 True, False, "/",
577 False, False, "1444312383.018307",
578 False, None, None,
579 {})
580 self.assertEqual(cookie.expires, 1444312383)
581
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000582 # XXX RFC 2965 expiry rules (some apply to V0 too)
583
584 def test_default_path(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000585 # RFC 2965
586 pol = DefaultCookiePolicy(rfc2965=True)
587
588 c = CookieJar(pol)
589 interact_2965(c, "http://www.acme.com/", 'spam="bar"; Version="1"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000590 self.assertIn("/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000591
592 c = CookieJar(pol)
593 interact_2965(c, "http://www.acme.com/blah", 'eggs="bar"; Version="1"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000594 self.assertIn("/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000595
596 c = CookieJar(pol)
597 interact_2965(c, "http://www.acme.com/blah/rhubarb",
598 'eggs="bar"; Version="1"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000599 self.assertIn("/blah/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000600
601 c = CookieJar(pol)
602 interact_2965(c, "http://www.acme.com/blah/rhubarb/",
603 'eggs="bar"; Version="1"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000604 self.assertIn("/blah/rhubarb/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000605
606 # Netscape
607
608 c = CookieJar()
609 interact_netscape(c, "http://www.acme.com/", 'spam="bar"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000610 self.assertIn("/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000611
612 c = CookieJar()
613 interact_netscape(c, "http://www.acme.com/blah", 'eggs="bar"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000614 self.assertIn("/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000615
616 c = CookieJar()
617 interact_netscape(c, "http://www.acme.com/blah/rhubarb", 'eggs="bar"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000618 self.assertIn("/blah", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000619
620 c = CookieJar()
621 interact_netscape(c, "http://www.acme.com/blah/rhubarb/", 'eggs="bar"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000622 self.assertIn("/blah/rhubarb", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000623
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000624 def test_default_path_with_query(self):
625 cj = CookieJar()
626 uri = "http://example.com/?spam/eggs"
627 value = 'eggs="bar"'
628 interact_netscape(cj, uri, value)
629 # Default path does not include query, so is "/", not "/?spam".
630 self.assertIn("/", cj._cookies["example.com"])
631 # Cookie is sent back to the same URI.
Ezio Melottib3aedd42010-11-20 19:04:17 +0000632 self.assertEqual(interact_netscape(cj, uri), value)
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000633
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000634 def test_escape_path(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000635 cases = [
636 # quoted safe
637 ("/foo%2f/bar", "/foo%2F/bar"),
638 ("/foo%2F/bar", "/foo%2F/bar"),
639 # quoted %
640 ("/foo%%/bar", "/foo%%/bar"),
641 # quoted unsafe
642 ("/fo%19o/bar", "/fo%19o/bar"),
643 ("/fo%7do/bar", "/fo%7Do/bar"),
644 # unquoted safe
645 ("/foo/bar&", "/foo/bar&"),
646 ("/foo//bar", "/foo//bar"),
647 ("\176/foo/bar", "\176/foo/bar"),
648 # unquoted unsafe
649 ("/foo\031/bar", "/foo%19/bar"),
650 ("/\175foo/bar", "/%7Dfoo/bar"),
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000651 # unicode, latin-1 range
652 ("/foo/bar\u00fc", "/foo/bar%C3%BC"), # UTF-8 encoded
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000653 # unicode
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000654 ("/foo/bar\uabcd", "/foo/bar%EA%AF%8D"), # UTF-8 encoded
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000655 ]
656 for arg, result in cases:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000657 self.assertEqual(escape_path(arg), result)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000658
659 def test_request_path(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000660 # with parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000661 req = urllib.request.Request(
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000662 "http://www.example.com/rheum/rhaponticum;"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000663 "foo=bar;sing=song?apples=pears&spam=eggs#ni")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000664 self.assertEqual(request_path(req),
665 "/rheum/rhaponticum;foo=bar;sing=song")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000666 # without parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000667 req = urllib.request.Request(
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000668 "http://www.example.com/rheum/rhaponticum?"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000669 "apples=pears&spam=eggs#ni")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000670 self.assertEqual(request_path(req), "/rheum/rhaponticum")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000671 # missing final slash
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000672 req = urllib.request.Request("http://www.example.com")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000673 self.assertEqual(request_path(req), "/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000674
675 def test_request_port(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000676 req = urllib.request.Request("http://www.acme.com:1234/",
677 headers={"Host": "www.acme.com:4321"})
Ezio Melottib3aedd42010-11-20 19:04:17 +0000678 self.assertEqual(request_port(req), "1234")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000679 req = urllib.request.Request("http://www.acme.com/",
680 headers={"Host": "www.acme.com:4321"})
Ezio Melottib3aedd42010-11-20 19:04:17 +0000681 self.assertEqual(request_port(req), DEFAULT_HTTP_PORT)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000682
683 def test_request_host(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000684 # this request is illegal (RFC2616, 14.2.3)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000685 req = urllib.request.Request("http://1.1.1.1/",
686 headers={"Host": "www.acme.com:80"})
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000687 # libwww-perl wants this response, but that seems wrong (RFC 2616,
688 # section 5.2, point 1., and RFC 2965 section 1, paragraph 3)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000689 #self.assertEqual(request_host(req), "www.acme.com")
690 self.assertEqual(request_host(req), "1.1.1.1")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000691 req = urllib.request.Request("http://www.acme.com/",
692 headers={"Host": "irrelevant.com"})
Ezio Melottib3aedd42010-11-20 19:04:17 +0000693 self.assertEqual(request_host(req), "www.acme.com")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000694 # port shouldn't be in request-host
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000695 req = urllib.request.Request("http://www.acme.com:2345/resource.html",
696 headers={"Host": "www.acme.com:5432"})
Ezio Melottib3aedd42010-11-20 19:04:17 +0000697 self.assertEqual(request_host(req), "www.acme.com")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000698
699 def test_is_HDN(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000700 self.assertTrue(is_HDN("foo.bar.com"))
701 self.assertTrue(is_HDN("1foo2.3bar4.5com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200702 self.assertFalse(is_HDN("192.168.1.1"))
703 self.assertFalse(is_HDN(""))
704 self.assertFalse(is_HDN("."))
705 self.assertFalse(is_HDN(".foo.bar.com"))
706 self.assertFalse(is_HDN("..foo"))
707 self.assertFalse(is_HDN("foo."))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000708
709 def test_reach(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000710 self.assertEqual(reach("www.acme.com"), ".acme.com")
711 self.assertEqual(reach("acme.com"), "acme.com")
712 self.assertEqual(reach("acme.local"), ".local")
713 self.assertEqual(reach(".local"), ".local")
714 self.assertEqual(reach(".com"), ".com")
715 self.assertEqual(reach("."), ".")
716 self.assertEqual(reach(""), "")
717 self.assertEqual(reach("192.168.0.1"), "192.168.0.1")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000718
719 def test_domain_match(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000720 self.assertTrue(domain_match("192.168.1.1", "192.168.1.1"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200721 self.assertFalse(domain_match("192.168.1.1", ".168.1.1"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000722 self.assertTrue(domain_match("x.y.com", "x.Y.com"))
723 self.assertTrue(domain_match("x.y.com", ".Y.com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200724 self.assertFalse(domain_match("x.y.com", "Y.com"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000725 self.assertTrue(domain_match("a.b.c.com", ".c.com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200726 self.assertFalse(domain_match(".c.com", "a.b.c.com"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000727 self.assertTrue(domain_match("example.local", ".local"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200728 self.assertFalse(domain_match("blah.blah", ""))
729 self.assertFalse(domain_match("", ".rhubarb.rhubarb"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000730 self.assertTrue(domain_match("", ""))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000731
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000732 self.assertTrue(user_domain_match("acme.com", "acme.com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200733 self.assertFalse(user_domain_match("acme.com", ".acme.com"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000734 self.assertTrue(user_domain_match("rhubarb.acme.com", ".acme.com"))
735 self.assertTrue(user_domain_match("www.rhubarb.acme.com", ".acme.com"))
736 self.assertTrue(user_domain_match("x.y.com", "x.Y.com"))
737 self.assertTrue(user_domain_match("x.y.com", ".Y.com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200738 self.assertFalse(user_domain_match("x.y.com", "Y.com"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000739 self.assertTrue(user_domain_match("y.com", "Y.com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200740 self.assertFalse(user_domain_match(".y.com", "Y.com"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000741 self.assertTrue(user_domain_match(".y.com", ".Y.com"))
742 self.assertTrue(user_domain_match("x.y.com", ".com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200743 self.assertFalse(user_domain_match("x.y.com", "com"))
744 self.assertFalse(user_domain_match("x.y.com", "m"))
745 self.assertFalse(user_domain_match("x.y.com", ".m"))
746 self.assertFalse(user_domain_match("x.y.com", ""))
747 self.assertFalse(user_domain_match("x.y.com", "."))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000748 self.assertTrue(user_domain_match("192.168.1.1", "192.168.1.1"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000749 # not both HDNs, so must string-compare equal to match
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200750 self.assertFalse(user_domain_match("192.168.1.1", ".168.1.1"))
751 self.assertFalse(user_domain_match("192.168.1.1", "."))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000752 # empty string is a special case
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200753 self.assertFalse(user_domain_match("192.168.1.1", ""))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000754
755 def test_wrong_domain(self):
756 # Cookies whose effective request-host name does not domain-match the
757 # domain are rejected.
758
759 # XXX far from complete
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000760 c = CookieJar()
761 interact_2965(c, "http://www.nasty.com/",
762 'foo=bar; domain=friendly.org; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000763 self.assertEqual(len(c), 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000764
Thomas Wouters477c8d52006-05-27 19:21:47 +0000765 def test_strict_domain(self):
766 # Cookies whose domain is a country-code tld like .co.uk should
767 # not be set if CookiePolicy.strict_domain is true.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000768 cp = DefaultCookiePolicy(strict_domain=True)
769 cj = CookieJar(policy=cp)
770 interact_netscape(cj, "http://example.co.uk/", 'no=problemo')
771 interact_netscape(cj, "http://example.co.uk/",
772 'okey=dokey; Domain=.example.co.uk')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000773 self.assertEqual(len(cj), 2)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000774 for pseudo_tld in [".co.uk", ".org.za", ".tx.us", ".name.us"]:
775 interact_netscape(cj, "http://example.%s/" % pseudo_tld,
776 'spam=eggs; Domain=.co.uk')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000777 self.assertEqual(len(cj), 2)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000778
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000779 def test_two_component_domain_ns(self):
780 # Netscape: .www.bar.com, www.bar.com, .bar.com, bar.com, no domain
781 # should all get accepted, as should .acme.com, acme.com and no domain
782 # for 2-component domains like acme.com.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000783 c = CookieJar()
784
785 # two-component V0 domain is OK
786 interact_netscape(c, "http://foo.net/", 'ns=bar')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000787 self.assertEqual(len(c), 1)
788 self.assertEqual(c._cookies["foo.net"]["/"]["ns"].value, "bar")
789 self.assertEqual(interact_netscape(c, "http://foo.net/"), "ns=bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000790 # *will* be returned to any other domain (unlike RFC 2965)...
Ezio Melottib3aedd42010-11-20 19:04:17 +0000791 self.assertEqual(interact_netscape(c, "http://www.foo.net/"),
792 "ns=bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000793 # ...unless requested otherwise
794 pol = DefaultCookiePolicy(
795 strict_ns_domain=DefaultCookiePolicy.DomainStrictNonDomain)
796 c.set_policy(pol)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000797 self.assertEqual(interact_netscape(c, "http://www.foo.net/"), "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000798
799 # unlike RFC 2965, even explicit two-component domain is OK,
800 # because .foo.net matches foo.net
801 interact_netscape(c, "http://foo.net/foo/",
802 'spam1=eggs; domain=foo.net')
803 # even if starts with a dot -- in NS rules, .foo.net matches foo.net!
804 interact_netscape(c, "http://foo.net/foo/bar/",
805 'spam2=eggs; domain=.foo.net')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000806 self.assertEqual(len(c), 3)
807 self.assertEqual(c._cookies[".foo.net"]["/foo"]["spam1"].value,
808 "eggs")
809 self.assertEqual(c._cookies[".foo.net"]["/foo/bar"]["spam2"].value,
810 "eggs")
811 self.assertEqual(interact_netscape(c, "http://foo.net/foo/bar/"),
812 "spam2=eggs; spam1=eggs; ns=bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000813
814 # top-level domain is too general
815 interact_netscape(c, "http://foo.net/", 'nini="ni"; domain=.net')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000816 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000817
818## # Netscape protocol doesn't allow non-special top level domains (such
819## # as co.uk) in the domain attribute unless there are at least three
820## # dots in it.
821 # Oh yes it does! Real implementations don't check this, and real
822 # cookies (of course) rely on that behaviour.
823 interact_netscape(c, "http://foo.co.uk", 'nasty=trick; domain=.co.uk')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000824## self.assertEqual(len(c), 2)
825 self.assertEqual(len(c), 4)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000826
827 def test_two_component_domain_rfc2965(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000828 pol = DefaultCookiePolicy(rfc2965=True)
829 c = CookieJar(pol)
830
831 # two-component V1 domain is OK
832 interact_2965(c, "http://foo.net/", 'foo=bar; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000833 self.assertEqual(len(c), 1)
834 self.assertEqual(c._cookies["foo.net"]["/"]["foo"].value, "bar")
835 self.assertEqual(interact_2965(c, "http://foo.net/"),
836 "$Version=1; foo=bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000837 # won't be returned to any other domain (because domain was implied)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000838 self.assertEqual(interact_2965(c, "http://www.foo.net/"), "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000839
840 # unless domain is given explicitly, because then it must be
841 # rewritten to start with a dot: foo.net --> .foo.net, which does
842 # not domain-match foo.net
843 interact_2965(c, "http://foo.net/foo",
844 'spam=eggs; domain=foo.net; path=/foo; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000845 self.assertEqual(len(c), 1)
846 self.assertEqual(interact_2965(c, "http://foo.net/foo"),
847 "$Version=1; foo=bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000848
849 # explicit foo.net from three-component domain www.foo.net *does* get
850 # set, because .foo.net domain-matches .foo.net
851 interact_2965(c, "http://www.foo.net/foo/",
852 'spam=eggs; domain=foo.net; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000853 self.assertEqual(c._cookies[".foo.net"]["/foo/"]["spam"].value,
854 "eggs")
855 self.assertEqual(len(c), 2)
856 self.assertEqual(interact_2965(c, "http://foo.net/foo/"),
857 "$Version=1; foo=bar")
858 self.assertEqual(interact_2965(c, "http://www.foo.net/foo/"),
859 '$Version=1; spam=eggs; $Domain="foo.net"')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000860
861 # top-level domain is too general
862 interact_2965(c, "http://foo.net/",
863 'ni="ni"; domain=".net"; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000864 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000865
866 # RFC 2965 doesn't require blocking this
867 interact_2965(c, "http://foo.co.uk/",
868 'nasty=trick; domain=.co.uk; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000869 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000870
871 def test_domain_allow(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000872 c = CookieJar(policy=DefaultCookiePolicy(
873 blocked_domains=["acme.com"],
874 allowed_domains=["www.acme.com"]))
875
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000876 req = urllib.request.Request("http://acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000877 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
878 res = FakeResponse(headers, "http://acme.com/")
879 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000880 self.assertEqual(len(c), 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000881
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000882 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000883 res = FakeResponse(headers, "http://www.acme.com/")
884 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000885 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000886
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000887 req = urllib.request.Request("http://www.coyote.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000888 res = FakeResponse(headers, "http://www.coyote.com/")
889 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000890 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000891
892 # set a cookie with non-allowed domain...
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000893 req = urllib.request.Request("http://www.coyote.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000894 res = FakeResponse(headers, "http://www.coyote.com/")
895 cookies = c.make_cookies(res, req)
896 c.set_cookie(cookies[0])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000897 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000898 # ... and check is doesn't get returned
899 c.add_cookie_header(req)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200900 self.assertFalse(req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000901
902 def test_domain_block(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000903 pol = DefaultCookiePolicy(
904 rfc2965=True, blocked_domains=[".acme.com"])
905 c = CookieJar(policy=pol)
906 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
907
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000908 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000909 res = FakeResponse(headers, "http://www.acme.com/")
910 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000911 self.assertEqual(len(c), 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000912
913 p = pol.set_blocked_domains(["acme.com"])
914 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000915 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000916
917 c.clear()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000918 req = urllib.request.Request("http://www.roadrunner.net/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000919 res = FakeResponse(headers, "http://www.roadrunner.net/")
920 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000921 self.assertEqual(len(c), 1)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000922 req = urllib.request.Request("http://www.roadrunner.net/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000923 c.add_cookie_header(req)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200924 self.assertTrue(req.has_header("Cookie"))
925 self.assertTrue(req.has_header("Cookie2"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000926
927 c.clear()
928 pol.set_blocked_domains([".acme.com"])
929 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000930 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000931
932 # set a cookie with blocked domain...
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000933 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000934 res = FakeResponse(headers, "http://www.acme.com/")
935 cookies = c.make_cookies(res, req)
936 c.set_cookie(cookies[0])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000937 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000938 # ... and check is doesn't get returned
939 c.add_cookie_header(req)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200940 self.assertFalse(req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000941
942 def test_secure(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000943 for ns in True, False:
944 for whitespace in " ", "":
945 c = CookieJar()
946 if ns:
947 pol = DefaultCookiePolicy(rfc2965=False)
948 int = interact_netscape
949 vs = ""
950 else:
951 pol = DefaultCookiePolicy(rfc2965=True)
952 int = interact_2965
953 vs = "; Version=1"
954 c.set_policy(pol)
955 url = "http://www.acme.com/"
956 int(c, url, "foo1=bar%s%s" % (vs, whitespace))
957 int(c, url, "foo2=bar%s; secure%s" % (vs, whitespace))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200958 self.assertFalse(
959 c._cookies["www.acme.com"]["/"]["foo1"].secure,
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000960 "non-secure cookie registered secure")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000961 self.assertTrue(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000962 c._cookies["www.acme.com"]["/"]["foo2"].secure,
963 "secure cookie registered non-secure")
964
965 def test_quote_cookie_value(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000966 c = CookieJar(policy=DefaultCookiePolicy(rfc2965=True))
967 interact_2965(c, "http://www.acme.com/", r'foo=\b"a"r; Version=1')
968 h = interact_2965(c, "http://www.acme.com/")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000969 self.assertEqual(h, r'$Version=1; foo=\\b\"a\"r')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000970
971 def test_missing_final_slash(self):
972 # Missing slash from request URL's abs_path should be assumed present.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000973 url = "http://www.acme.com"
974 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
975 interact_2965(c, url, "foo=bar; Version=1")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000976 req = urllib.request.Request(url)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000977 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000978 c.add_cookie_header(req)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000979 self.assertTrue(req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000980
981 def test_domain_mirror(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000982 pol = DefaultCookiePolicy(rfc2965=True)
983
984 c = CookieJar(pol)
985 url = "http://foo.bar.com/"
986 interact_2965(c, url, "spam=eggs; Version=1")
987 h = interact_2965(c, url)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000988 self.assertNotIn("Domain", h,
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000989 "absent domain returned with domain present")
990
991 c = CookieJar(pol)
992 url = "http://foo.bar.com/"
993 interact_2965(c, url, 'spam=eggs; Version=1; Domain=.bar.com')
994 h = interact_2965(c, url)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000995 self.assertIn('$Domain=".bar.com"', h, "domain not returned")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000996
997 c = CookieJar(pol)
998 url = "http://foo.bar.com/"
999 # note missing initial dot in Domain
1000 interact_2965(c, url, 'spam=eggs; Version=1; Domain=bar.com')
1001 h = interact_2965(c, url)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001002 self.assertIn('$Domain="bar.com"', h, "domain not returned")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001003
1004 def test_path_mirror(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001005 pol = DefaultCookiePolicy(rfc2965=True)
1006
1007 c = CookieJar(pol)
1008 url = "http://foo.bar.com/"
1009 interact_2965(c, url, "spam=eggs; Version=1")
1010 h = interact_2965(c, url)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001011 self.assertNotIn("Path", h, "absent path returned with path present")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001012
1013 c = CookieJar(pol)
1014 url = "http://foo.bar.com/"
1015 interact_2965(c, url, 'spam=eggs; Version=1; Path=/')
1016 h = interact_2965(c, url)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001017 self.assertIn('$Path="/"', h, "path not returned")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001018
1019 def test_port_mirror(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001020 pol = DefaultCookiePolicy(rfc2965=True)
1021
1022 c = CookieJar(pol)
1023 url = "http://foo.bar.com/"
1024 interact_2965(c, url, "spam=eggs; Version=1")
1025 h = interact_2965(c, url)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001026 self.assertNotIn("Port", h, "absent port returned with port present")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001027
1028 c = CookieJar(pol)
1029 url = "http://foo.bar.com/"
1030 interact_2965(c, url, "spam=eggs; Version=1; Port")
1031 h = interact_2965(c, url)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001032 self.assertRegex(h, "\$Port([^=]|$)",
1033 "port with no value not returned with no value")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001034
1035 c = CookieJar(pol)
1036 url = "http://foo.bar.com/"
1037 interact_2965(c, url, 'spam=eggs; Version=1; Port="80"')
1038 h = interact_2965(c, url)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001039 self.assertIn('$Port="80"', h,
1040 "port with single value not returned with single value")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001041
1042 c = CookieJar(pol)
1043 url = "http://foo.bar.com/"
1044 interact_2965(c, url, 'spam=eggs; Version=1; Port="80,8080"')
1045 h = interact_2965(c, url)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001046 self.assertIn('$Port="80,8080"', h,
1047 "port with multiple values not returned with multiple "
1048 "values")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001049
1050 def test_no_return_comment(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001051 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1052 url = "http://foo.bar.com/"
1053 interact_2965(c, url, 'spam=eggs; Version=1; '
1054 'Comment="does anybody read these?"; '
1055 'CommentURL="http://foo.bar.net/comment.html"')
1056 h = interact_2965(c, url)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001057 self.assertNotIn("Comment", h,
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001058 "Comment or CommentURL cookie-attributes returned to server")
1059
1060 def test_Cookie_iterator(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001061 cs = CookieJar(DefaultCookiePolicy(rfc2965=True))
1062 # add some random cookies
1063 interact_2965(cs, "http://blah.spam.org/", 'foo=eggs; Version=1; '
1064 'Comment="does anybody read these?"; '
1065 'CommentURL="http://foo.bar.net/comment.html"')
1066 interact_netscape(cs, "http://www.acme.com/blah/", "spam=bar; secure")
1067 interact_2965(cs, "http://www.acme.com/blah/",
1068 "foo=bar; secure; Version=1")
1069 interact_2965(cs, "http://www.acme.com/blah/",
1070 "foo=bar; path=/; Version=1")
1071 interact_2965(cs, "http://www.sol.no",
1072 r'bang=wallop; version=1; domain=".sol.no"; '
1073 r'port="90,100, 80,8080"; '
1074 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "')
1075
1076 versions = [1, 1, 1, 0, 1]
1077 names = ["bang", "foo", "foo", "spam", "foo"]
1078 domains = [".sol.no", "blah.spam.org", "www.acme.com",
1079 "www.acme.com", "www.acme.com"]
1080 paths = ["/", "/", "/", "/blah", "/blah/"]
1081
1082 for i in range(4):
1083 i = 0
1084 for c in cs:
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001085 self.assertIsInstance(c, Cookie)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001086 self.assertEqual(c.version, versions[i])
1087 self.assertEqual(c.name, names[i])
1088 self.assertEqual(c.domain, domains[i])
1089 self.assertEqual(c.path, paths[i])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001090 i = i + 1
1091
1092 def test_parse_ns_headers(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001093 # missing domain value (invalid cookie)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001094 self.assertEqual(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001095 parse_ns_headers(["foo=bar; path=/; domain"]),
1096 [[("foo", "bar"),
1097 ("path", "/"), ("domain", None), ("version", "0")]]
1098 )
1099 # invalid expires value
Ezio Melottib3aedd42010-11-20 19:04:17 +00001100 self.assertEqual(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001101 parse_ns_headers(["foo=bar; expires=Foo Bar 12 33:22:11 2000"]),
1102 [[("foo", "bar"), ("expires", None), ("version", "0")]]
1103 )
1104 # missing cookie value (valid cookie)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001105 self.assertEqual(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001106 parse_ns_headers(["foo"]),
1107 [[("foo", None), ("version", "0")]]
1108 )
Serhiy Storchaka577fc4e2015-03-13 09:05:01 +02001109 # missing cookie values for parsed attributes
1110 self.assertEqual(
1111 parse_ns_headers(['foo=bar; expires']),
1112 [[('foo', 'bar'), ('expires', None), ('version', '0')]])
1113 self.assertEqual(
1114 parse_ns_headers(['foo=bar; version']),
1115 [[('foo', 'bar'), ('version', None)]])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001116 # shouldn't add version if header is empty
Ezio Melottib3aedd42010-11-20 19:04:17 +00001117 self.assertEqual(parse_ns_headers([""]), [])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001118
1119 def test_bad_cookie_header(self):
1120
1121 def cookiejar_from_cookie_headers(headers):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001122 c = CookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001123 req = urllib.request.Request("http://www.example.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001124 r = FakeResponse(headers, "http://www.example.com/")
1125 c.extract_cookies(r, req)
1126 return c
1127
Serhiy Storchaka577fc4e2015-03-13 09:05:01 +02001128 future = time2netscape(time.time()+3600)
1129
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001130 # none of these bad headers should cause an exception to be raised
1131 for headers in [
1132 ["Set-Cookie: "], # actually, nothing wrong with this
1133 ["Set-Cookie2: "], # ditto
1134 # missing domain value
1135 ["Set-Cookie2: a=foo; path=/; Version=1; domain"],
1136 # bad max-age
1137 ["Set-Cookie: b=foo; max-age=oops"],
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +00001138 # bad version
1139 ["Set-Cookie: b=foo; version=spam"],
Serhiy Storchaka577fc4e2015-03-13 09:05:01 +02001140 ["Set-Cookie:; Expires=%s" % future],
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001141 ]:
1142 c = cookiejar_from_cookie_headers(headers)
1143 # these bad cookies shouldn't be set
Ezio Melottib3aedd42010-11-20 19:04:17 +00001144 self.assertEqual(len(c), 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001145
1146 # cookie with invalid expires is treated as session cookie
1147 headers = ["Set-Cookie: c=foo; expires=Foo Bar 12 33:22:11 2000"]
1148 c = cookiejar_from_cookie_headers(headers)
1149 cookie = c._cookies["www.example.com"]["/"]["c"]
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001150 self.assertIsNone(cookie.expires)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001151
1152
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +00001153class LWPCookieTests(unittest.TestCase):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001154 # Tests taken from libwww-perl, with a few modifications and additions.
1155
1156 def test_netscape_example_1(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001157 #-------------------------------------------------------------------
1158 # First we check that it works for the original example at
1159 # http://www.netscape.com/newsref/std/cookie_spec.html
1160
1161 # Client requests a document, and receives in the response:
1162 #
1163 # Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
1164 #
1165 # When client requests a URL in path "/" on this server, it sends:
1166 #
1167 # Cookie: CUSTOMER=WILE_E_COYOTE
1168 #
1169 # Client requests a document, and receives in the response:
1170 #
1171 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
1172 #
1173 # When client requests a URL in path "/" on this server, it sends:
1174 #
1175 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
1176 #
1177 # Client receives:
1178 #
1179 # Set-Cookie: SHIPPING=FEDEX; path=/fo
1180 #
1181 # When client requests a URL in path "/" on this server, it sends:
1182 #
1183 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
1184 #
1185 # When client requests a URL in path "/foo" on this server, it sends:
1186 #
1187 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX
1188 #
1189 # The last Cookie is buggy, because both specifications say that the
1190 # most specific cookie must be sent first. SHIPPING=FEDEX is the
1191 # most specific and should thus be first.
1192
1193 year_plus_one = time.localtime()[0] + 1
1194
1195 headers = []
1196
1197 c = CookieJar(DefaultCookiePolicy(rfc2965 = True))
1198
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001199 #req = urllib.request.Request("http://1.1.1.1/",
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001200 # headers={"Host": "www.acme.com:80"})
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001201 req = urllib.request.Request("http://www.acme.com:80/",
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001202 headers={"Host": "www.acme.com:80"})
1203
1204 headers.append(
1205 "Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/ ; "
1206 "expires=Wednesday, 09-Nov-%d 23:12:40 GMT" % year_plus_one)
1207 res = FakeResponse(headers, "http://www.acme.com/")
1208 c.extract_cookies(res, req)
1209
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001210 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001211 c.add_cookie_header(req)
1212
1213 self.assertEqual(req.get_header("Cookie"), "CUSTOMER=WILE_E_COYOTE")
1214 self.assertEqual(req.get_header("Cookie2"), '$Version="1"')
1215
1216 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/")
1217 res = FakeResponse(headers, "http://www.acme.com/")
1218 c.extract_cookies(res, req)
1219
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001220 req = urllib.request.Request("http://www.acme.com/foo/bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001221 c.add_cookie_header(req)
1222
1223 h = req.get_header("Cookie")
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001224 self.assertIn("PART_NUMBER=ROCKET_LAUNCHER_0001", h)
1225 self.assertIn("CUSTOMER=WILE_E_COYOTE", h)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001226
1227 headers.append('Set-Cookie: SHIPPING=FEDEX; path=/foo')
1228 res = FakeResponse(headers, "http://www.acme.com")
1229 c.extract_cookies(res, req)
1230
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001231 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001232 c.add_cookie_header(req)
1233
1234 h = req.get_header("Cookie")
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001235 self.assertIn("PART_NUMBER=ROCKET_LAUNCHER_0001", h)
1236 self.assertIn("CUSTOMER=WILE_E_COYOTE", h)
1237 self.assertNotIn("SHIPPING=FEDEX", h)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001238
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001239 req = urllib.request.Request("http://www.acme.com/foo/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001240 c.add_cookie_header(req)
1241
1242 h = req.get_header("Cookie")
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001243 self.assertIn("PART_NUMBER=ROCKET_LAUNCHER_0001", h)
1244 self.assertIn("CUSTOMER=WILE_E_COYOTE", h)
1245 self.assertTrue(h.startswith("SHIPPING=FEDEX;"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001246
1247 def test_netscape_example_2(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001248 # Second Example transaction sequence:
1249 #
1250 # Assume all mappings from above have been cleared.
1251 #
1252 # Client receives:
1253 #
1254 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
1255 #
1256 # When client requests a URL in path "/" on this server, it sends:
1257 #
1258 # Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
1259 #
1260 # Client receives:
1261 #
1262 # Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
1263 #
1264 # When client requests a URL in path "/ammo" on this server, it sends:
1265 #
1266 # Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
1267 #
1268 # NOTE: There are two name/value pairs named "PART_NUMBER" due to
1269 # the inheritance of the "/" mapping in addition to the "/ammo" mapping.
1270
1271 c = CookieJar()
1272 headers = []
1273
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001274 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001275 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/")
1276 res = FakeResponse(headers, "http://www.acme.com/")
1277
1278 c.extract_cookies(res, req)
1279
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001280 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001281 c.add_cookie_header(req)
1282
Ezio Melottib3aedd42010-11-20 19:04:17 +00001283 self.assertEqual(req.get_header("Cookie"),
1284 "PART_NUMBER=ROCKET_LAUNCHER_0001")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001285
1286 headers.append(
1287 "Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo")
1288 res = FakeResponse(headers, "http://www.acme.com/")
1289 c.extract_cookies(res, req)
1290
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001291 req = urllib.request.Request("http://www.acme.com/ammo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001292 c.add_cookie_header(req)
1293
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001294 self.assertRegex(req.get_header("Cookie"),
1295 r"PART_NUMBER=RIDING_ROCKET_0023;\s*"
1296 "PART_NUMBER=ROCKET_LAUNCHER_0001")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001297
1298 def test_ietf_example_1(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001299 #-------------------------------------------------------------------
1300 # Then we test with the examples from draft-ietf-http-state-man-mec-03.txt
1301 #
1302 # 5. EXAMPLES
1303
1304 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1305
1306 #
1307 # 5.1 Example 1
1308 #
1309 # Most detail of request and response headers has been omitted. Assume
1310 # the user agent has no stored cookies.
1311 #
1312 # 1. User Agent -> Server
1313 #
1314 # POST /acme/login HTTP/1.1
1315 # [form data]
1316 #
1317 # User identifies self via a form.
1318 #
1319 # 2. Server -> User Agent
1320 #
1321 # HTTP/1.1 200 OK
1322 # Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
1323 #
1324 # Cookie reflects user's identity.
1325
1326 cookie = interact_2965(
1327 c, 'http://www.acme.com/acme/login',
1328 'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"')
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001329 self.assertFalse(cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001330
1331 #
1332 # 3. User Agent -> Server
1333 #
1334 # POST /acme/pickitem HTTP/1.1
1335 # Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
1336 # [form data]
1337 #
1338 # User selects an item for ``shopping basket.''
1339 #
1340 # 4. Server -> User Agent
1341 #
1342 # HTTP/1.1 200 OK
1343 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
1344 # Path="/acme"
1345 #
1346 # Shopping basket contains an item.
1347
1348 cookie = interact_2965(c, 'http://www.acme.com/acme/pickitem',
1349 'Part_Number="Rocket_Launcher_0001"; '
1350 'Version="1"; Path="/acme"');
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001351 self.assertRegex(cookie,
1352 r'^\$Version="?1"?; Customer="?WILE_E_COYOTE"?; \$Path="/acme"$')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001353
1354 #
1355 # 5. User Agent -> Server
1356 #
1357 # POST /acme/shipping HTTP/1.1
1358 # Cookie: $Version="1";
1359 # Customer="WILE_E_COYOTE"; $Path="/acme";
1360 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1361 # [form data]
1362 #
1363 # User selects shipping method from form.
1364 #
1365 # 6. Server -> User Agent
1366 #
1367 # HTTP/1.1 200 OK
1368 # Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"
1369 #
1370 # New cookie reflects shipping method.
1371
1372 cookie = interact_2965(c, "http://www.acme.com/acme/shipping",
1373 'Shipping="FedEx"; Version="1"; Path="/acme"')
1374
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001375 self.assertRegex(cookie, r'^\$Version="?1"?;')
1376 self.assertRegex(cookie, r'Part_Number="?Rocket_Launcher_0001"?;'
1377 '\s*\$Path="\/acme"')
1378 self.assertRegex(cookie, r'Customer="?WILE_E_COYOTE"?;'
1379 '\s*\$Path="\/acme"')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001380
1381 #
1382 # 7. User Agent -> Server
1383 #
1384 # POST /acme/process HTTP/1.1
1385 # Cookie: $Version="1";
1386 # Customer="WILE_E_COYOTE"; $Path="/acme";
1387 # Part_Number="Rocket_Launcher_0001"; $Path="/acme";
1388 # Shipping="FedEx"; $Path="/acme"
1389 # [form data]
1390 #
1391 # User chooses to process order.
1392 #
1393 # 8. Server -> User Agent
1394 #
1395 # HTTP/1.1 200 OK
1396 #
1397 # Transaction is complete.
1398
1399 cookie = interact_2965(c, "http://www.acme.com/acme/process")
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001400 self.assertRegex(cookie, r'Shipping="?FedEx"?;\s*\$Path="\/acme"')
1401 self.assertIn("WILE_E_COYOTE", cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001402
1403 #
1404 # The user agent makes a series of requests on the origin server, after
1405 # each of which it receives a new cookie. All the cookies have the same
1406 # Path attribute and (default) domain. Because the request URLs all have
1407 # /acme as a prefix, and that matches the Path attribute, each request
1408 # contains all the cookies received so far.
1409
1410 def test_ietf_example_2(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001411 # 5.2 Example 2
1412 #
1413 # This example illustrates the effect of the Path attribute. All detail
1414 # of request and response headers has been omitted. Assume the user agent
1415 # has no stored cookies.
1416
1417 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1418
1419 # Imagine the user agent has received, in response to earlier requests,
1420 # the response headers
1421 #
1422 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
1423 # Path="/acme"
1424 #
1425 # and
1426 #
1427 # Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1";
1428 # Path="/acme/ammo"
1429
1430 interact_2965(
1431 c, "http://www.acme.com/acme/ammo/specific",
1432 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"',
1433 'Part_Number="Riding_Rocket_0023"; Version="1"; Path="/acme/ammo"')
1434
1435 # A subsequent request by the user agent to the (same) server for URLs of
1436 # the form /acme/ammo/... would include the following request header:
1437 #
1438 # Cookie: $Version="1";
1439 # Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
1440 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1441 #
1442 # Note that the NAME=VALUE pair for the cookie with the more specific Path
1443 # attribute, /acme/ammo, comes before the one with the less specific Path
1444 # attribute, /acme. Further note that the same cookie name appears more
1445 # than once.
1446
1447 cookie = interact_2965(c, "http://www.acme.com/acme/ammo/...")
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001448 self.assertRegex(cookie, r"Riding_Rocket_0023.*Rocket_Launcher_0001")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001449
1450 # A subsequent request by the user agent to the (same) server for a URL of
1451 # the form /acme/parts/ would include the following request header:
1452 #
1453 # Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1454 #
1455 # Here, the second cookie's Path attribute /acme/ammo is not a prefix of
1456 # the request URL, /acme/parts/, so the cookie does not get forwarded to
1457 # the server.
1458
1459 cookie = interact_2965(c, "http://www.acme.com/acme/parts/")
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001460 self.assertIn("Rocket_Launcher_0001", cookie)
1461 self.assertNotIn("Riding_Rocket_0023", cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001462
1463 def test_rejection(self):
1464 # Test rejection of Set-Cookie2 responses based on domain, path, port.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001465 pol = DefaultCookiePolicy(rfc2965=True)
1466
1467 c = LWPCookieJar(policy=pol)
1468
1469 max_age = "max-age=3600"
1470
1471 # illegal domain (no embedded dots)
1472 cookie = interact_2965(c, "http://www.acme.com",
1473 'foo=bar; domain=".com"; version=1')
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001474 self.assertFalse(c)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001475
1476 # legal domain
1477 cookie = interact_2965(c, "http://www.acme.com",
1478 'ping=pong; domain="acme.com"; version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001479 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001480
1481 # illegal domain (host prefix "www.a" contains a dot)
1482 cookie = interact_2965(c, "http://www.a.acme.com",
1483 'whiz=bang; domain="acme.com"; version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001484 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001485
1486 # legal domain
1487 cookie = interact_2965(c, "http://www.a.acme.com",
1488 'wow=flutter; domain=".a.acme.com"; version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001489 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001490
1491 # can't partially match an IP-address
1492 cookie = interact_2965(c, "http://125.125.125.125",
1493 'zzzz=ping; domain="125.125.125"; version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001494 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001495
1496 # illegal path (must be prefix of request path)
1497 cookie = interact_2965(c, "http://www.sol.no",
1498 'blah=rhubarb; domain=".sol.no"; path="/foo"; '
1499 'version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001500 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001501
1502 # legal path
1503 cookie = interact_2965(c, "http://www.sol.no/foo/bar",
1504 'bing=bong; domain=".sol.no"; path="/foo"; '
1505 'version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001506 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001507
1508 # illegal port (request-port not in list)
1509 cookie = interact_2965(c, "http://www.sol.no",
1510 'whiz=ffft; domain=".sol.no"; port="90,100"; '
1511 'version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001512 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001513
1514 # legal port
1515 cookie = interact_2965(
1516 c, "http://www.sol.no",
1517 r'bang=wallop; version=1; domain=".sol.no"; '
1518 r'port="90,100, 80,8080"; '
1519 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001520 self.assertEqual(len(c), 4)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001521
1522 # port attribute without any value (current port)
1523 cookie = interact_2965(c, "http://www.sol.no",
1524 'foo9=bar; version=1; domain=".sol.no"; port; '
1525 'max-age=100;')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001526 self.assertEqual(len(c), 5)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001527
1528 # encoded path
1529 # LWP has this test, but unescaping allowed path characters seems
1530 # like a bad idea, so I think this should fail:
1531## cookie = interact_2965(c, "http://www.sol.no/foo/",
1532## r'foo8=bar; version=1; path="/%66oo"')
1533 # but this is OK, because '<' is not an allowed HTTP URL path
1534 # character:
1535 cookie = interact_2965(c, "http://www.sol.no/<oo/",
1536 r'foo8=bar; version=1; path="/%3coo"')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001537 self.assertEqual(len(c), 6)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001538
1539 # save and restore
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +00001540 filename = test.support.TESTFN
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001541
1542 try:
1543 c.save(filename, ignore_discard=True)
1544 old = repr(c)
1545
1546 c = LWPCookieJar(policy=pol)
1547 c.load(filename, ignore_discard=True)
1548 finally:
1549 try: os.unlink(filename)
1550 except OSError: pass
1551
Ezio Melottib3aedd42010-11-20 19:04:17 +00001552 self.assertEqual(old, repr(c))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001553
1554 def test_url_encoding(self):
1555 # Try some URL encodings of the PATHs.
1556 # (the behaviour here has changed from libwww-perl)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001557 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001558 interact_2965(c, "http://www.acme.com/foo%2f%25/"
1559 "%3c%3c%0Anew%C3%A5/%C3%A5",
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001560 "foo = bar; version = 1")
1561
1562 cookie = interact_2965(
Guido van Rossumf520c052007-07-23 03:46:37 +00001563 c, "http://www.acme.com/foo%2f%25/<<%0anew\345/\346\370\345",
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001564 'bar=baz; path="/foo/"; version=1');
1565 version_re = re.compile(r'^\$version=\"?1\"?', re.I)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001566 self.assertIn("foo=bar", cookie)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001567 self.assertRegex(cookie, version_re)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001568
1569 cookie = interact_2965(
Guido van Rossumf520c052007-07-23 03:46:37 +00001570 c, "http://www.acme.com/foo/%25/<<%0anew\345/\346\370\345")
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001571 self.assertFalse(cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001572
1573 # unicode URL doesn't raise exception
Guido van Rossumef87d6e2007-05-02 19:09:54 +00001574 cookie = interact_2965(c, "http://www.acme.com/\xfc")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001575
1576 def test_mozilla(self):
1577 # Save / load Mozilla/Netscape cookie file format.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001578 year_plus_one = time.localtime()[0] + 1
1579
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +00001580 filename = test.support.TESTFN
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001581
1582 c = MozillaCookieJar(filename,
1583 policy=DefaultCookiePolicy(rfc2965=True))
1584 interact_2965(c, "http://www.acme.com/",
1585 "foo1=bar; max-age=100; Version=1")
1586 interact_2965(c, "http://www.acme.com/",
1587 'foo2=bar; port="80"; max-age=100; Discard; Version=1')
1588 interact_2965(c, "http://www.acme.com/", "foo3=bar; secure; Version=1")
1589
1590 expires = "expires=09-Nov-%d 23:12:40 GMT" % (year_plus_one,)
1591 interact_netscape(c, "http://www.foo.com/",
1592 "fooa=bar; %s" % expires)
1593 interact_netscape(c, "http://www.foo.com/",
1594 "foob=bar; Domain=.foo.com; %s" % expires)
1595 interact_netscape(c, "http://www.foo.com/",
1596 "fooc=bar; Domain=www.foo.com; %s" % expires)
1597
1598 def save_and_restore(cj, ignore_discard):
1599 try:
1600 cj.save(ignore_discard=ignore_discard)
1601 new_c = MozillaCookieJar(filename,
1602 DefaultCookiePolicy(rfc2965=True))
1603 new_c.load(ignore_discard=ignore_discard)
1604 finally:
1605 try: os.unlink(filename)
1606 except OSError: pass
1607 return new_c
1608
1609 new_c = save_and_restore(c, True)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001610 self.assertEqual(len(new_c), 6) # none discarded
Benjamin Peterson577473f2010-01-19 00:09:57 +00001611 self.assertIn("name='foo1', value='bar'", repr(new_c))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001612
1613 new_c = save_and_restore(c, False)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001614 self.assertEqual(len(new_c), 4) # 2 of them discarded on save
Benjamin Peterson577473f2010-01-19 00:09:57 +00001615 self.assertIn("name='foo1', value='bar'", repr(new_c))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001616
1617 def test_netscape_misc(self):
1618 # Some additional Netscape cookies tests.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001619 c = CookieJar()
1620 headers = []
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001621 req = urllib.request.Request("http://foo.bar.acme.com/foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001622
1623 # Netscape allows a host part that contains dots
1624 headers.append("Set-Cookie: Customer=WILE_E_COYOTE; domain=.acme.com")
1625 res = FakeResponse(headers, "http://www.acme.com/foo")
1626 c.extract_cookies(res, req)
1627
1628 # and that the domain is the same as the host without adding a leading
1629 # dot to the domain. Should not quote even if strange chars are used
1630 # in the cookie value.
1631 headers.append("Set-Cookie: PART_NUMBER=3,4; domain=foo.bar.acme.com")
1632 res = FakeResponse(headers, "http://www.acme.com/foo")
1633 c.extract_cookies(res, req)
1634
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001635 req = urllib.request.Request("http://foo.bar.acme.com/foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001636 c.add_cookie_header(req)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001637 self.assertIn("PART_NUMBER=3,4", req.get_header("Cookie"))
1638 self.assertIn("Customer=WILE_E_COYOTE",req.get_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001639
1640 def test_intranet_domains_2965(self):
1641 # Test handling of local intranet hostnames without a dot.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001642 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1643 interact_2965(c, "http://example/",
1644 "foo1=bar; PORT; Discard; Version=1;")
1645 cookie = interact_2965(c, "http://example/",
1646 'foo2=bar; domain=".local"; Version=1')
Benjamin Peterson577473f2010-01-19 00:09:57 +00001647 self.assertIn("foo1=bar", cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001648
1649 interact_2965(c, "http://example/", 'foo3=bar; Version=1')
1650 cookie = interact_2965(c, "http://example/")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001651 self.assertIn("foo2=bar", cookie)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001652 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001653
1654 def test_intranet_domains_ns(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001655 c = CookieJar(DefaultCookiePolicy(rfc2965 = False))
1656 interact_netscape(c, "http://example/", "foo1=bar")
1657 cookie = interact_netscape(c, "http://example/",
1658 'foo2=bar; domain=.local')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001659 self.assertEqual(len(c), 2)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001660 self.assertIn("foo1=bar", cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001661
1662 cookie = interact_netscape(c, "http://example/")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001663 self.assertIn("foo2=bar", cookie)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001664 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001665
1666 def test_empty_path(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001667 # Test for empty path
1668 # Broken web-server ORION/1.3.38 returns to the client response like
1669 #
1670 # Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=
1671 #
1672 # ie. with Path set to nothing.
1673 # In this case, extract_cookies() must set cookie to / (root)
1674 c = CookieJar(DefaultCookiePolicy(rfc2965 = True))
1675 headers = []
1676
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001677 req = urllib.request.Request("http://www.ants.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001678 headers.append("Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=")
1679 res = FakeResponse(headers, "http://www.ants.com/")
1680 c.extract_cookies(res, req)
1681
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001682 req = urllib.request.Request("http://www.ants.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001683 c.add_cookie_header(req)
1684
Ezio Melottib3aedd42010-11-20 19:04:17 +00001685 self.assertEqual(req.get_header("Cookie"),
1686 "JSESSIONID=ABCDERANDOM123")
1687 self.assertEqual(req.get_header("Cookie2"), '$Version="1"')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001688
1689 # missing path in the request URI
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001690 req = urllib.request.Request("http://www.ants.com:8080")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001691 c.add_cookie_header(req)
1692
Ezio Melottib3aedd42010-11-20 19:04:17 +00001693 self.assertEqual(req.get_header("Cookie"),
1694 "JSESSIONID=ABCDERANDOM123")
1695 self.assertEqual(req.get_header("Cookie2"), '$Version="1"')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001696
1697 def test_session_cookies(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001698 year_plus_one = time.localtime()[0] + 1
1699
1700 # Check session cookies are deleted properly by
1701 # CookieJar.clear_session_cookies method
1702
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001703 req = urllib.request.Request('http://www.perlmeister.com/scripts')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001704 headers = []
1705 headers.append("Set-Cookie: s1=session;Path=/scripts")
1706 headers.append("Set-Cookie: p1=perm; Domain=.perlmeister.com;"
1707 "Path=/;expires=Fri, 02-Feb-%d 23:24:20 GMT" %
1708 year_plus_one)
1709 headers.append("Set-Cookie: p2=perm;Path=/;expires=Fri, "
1710 "02-Feb-%d 23:24:20 GMT" % year_plus_one)
1711 headers.append("Set-Cookie: s2=session;Path=/scripts;"
1712 "Domain=.perlmeister.com")
1713 headers.append('Set-Cookie2: s3=session;Version=1;Discard;Path="/"')
1714 res = FakeResponse(headers, 'http://www.perlmeister.com/scripts')
1715
1716 c = CookieJar()
1717 c.extract_cookies(res, req)
1718 # How many session/permanent cookies do we have?
1719 counter = {"session_after": 0,
1720 "perm_after": 0,
1721 "session_before": 0,
1722 "perm_before": 0}
1723 for cookie in c:
1724 key = "%s_before" % cookie.value
1725 counter[key] = counter[key] + 1
1726 c.clear_session_cookies()
1727 # How many now?
1728 for cookie in c:
1729 key = "%s_after" % cookie.value
1730 counter[key] = counter[key] + 1
1731
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001732 # a permanent cookie got lost accidently
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001733 self.assertEqual(counter["perm_after"], counter["perm_before"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001734 # a session cookie hasn't been cleared
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001735 self.assertEqual(counter["session_after"], 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001736 # we didn't have session cookies in the first place
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001737 self.assertNotEqual(counter["session_before"], 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001738
1739
1740def test_main(verbose=None):
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +00001741 test.support.run_unittest(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001742 DateTimeTests,
1743 HeaderTests,
1744 CookieTests,
Martin v. Löwisc5574e82005-03-03 10:57:37 +00001745 FileCookieJarTests,
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001746 LWPCookieTests,
1747 )
1748
1749if __name__ == "__main__":
1750 test_main(verbose=True)