blob: 6fee4df10a40f05f1a1c99e7a3cbb60320645785 [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
Senthil Kumarand5b47fb2016-07-10 06:45:38 -070034 def test_time2netscape(self):
35 base = 1019227000
36 day = 24*3600
37 self.assertEqual(time2netscape(base), "Fri, 19-Apr-2002 14:36:40 GMT")
38 self.assertEqual(time2netscape(base+day),
39 "Sat, 20-Apr-2002 14:36:40 GMT")
40
41 self.assertEqual(time2netscape(base+2*day),
42 "Sun, 21-Apr-2002 14:36:40 GMT")
43
44 self.assertEqual(time2netscape(base+3*day),
45 "Mon, 22-Apr-2002 14:36:40 GMT")
46
47 az = time2netscape()
48 bz = time2netscape(500000)
49 for text in (az, bz):
50 # Format "%s, %02d-%s-%04d %02d:%02d:%02d GMT"
51 self.assertRegex(
52 text,
53 r"[a-zA-Z]{3}, \d{2}-[a-zA-Z]{3}-\d{4} \d{2}:\d{2}:\d{2} GMT$",
54 "bad time2netscape format: %s %s" % (az, bz))
55
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000056 def test_http2time(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000057 def parse_date(text):
58 return time.gmtime(http2time(text))[:6]
59
Ezio Melottib3aedd42010-11-20 19:04:17 +000060 self.assertEqual(parse_date("01 Jan 2001"), (2001, 1, 1, 0, 0, 0.0))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000061
62 # this test will break around year 2070
Ezio Melottib3aedd42010-11-20 19:04:17 +000063 self.assertEqual(parse_date("03-Feb-20"), (2020, 2, 3, 0, 0, 0.0))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000064
65 # this test will break around year 2048
Ezio Melottib3aedd42010-11-20 19:04:17 +000066 self.assertEqual(parse_date("03-Feb-98"), (1998, 2, 3, 0, 0, 0.0))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000067
68 def test_http2time_formats(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000069 # test http2time for supported dates. Test cases with 2 digit year
70 # will probably break in year 2044.
71 tests = [
72 'Thu, 03 Feb 1994 00:00:00 GMT', # proposed new HTTP format
73 'Thursday, 03-Feb-94 00:00:00 GMT', # old rfc850 HTTP format
74 'Thursday, 03-Feb-1994 00:00:00 GMT', # broken rfc850 HTTP format
75
76 '03 Feb 1994 00:00:00 GMT', # HTTP format (no weekday)
77 '03-Feb-94 00:00:00 GMT', # old rfc850 (no weekday)
78 '03-Feb-1994 00:00:00 GMT', # broken rfc850 (no weekday)
79 '03-Feb-1994 00:00 GMT', # broken rfc850 (no weekday, no seconds)
80 '03-Feb-1994 00:00', # broken rfc850 (no weekday, no seconds, no tz)
Ezio Melotti7ac17f82013-08-10 18:07:25 +030081 '02-Feb-1994 24:00', # broken rfc850 (no weekday, no seconds,
82 # no tz) using hour 24 with yesterday date
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000083
84 '03-Feb-94', # old rfc850 HTTP format (no weekday, no time)
85 '03-Feb-1994', # broken rfc850 HTTP format (no weekday, no time)
86 '03 Feb 1994', # proposed new HTTP format (no weekday, no time)
87
88 # A few tests with extra space at various places
89 ' 03 Feb 1994 0:00 ',
90 ' 03-Feb-1994 ',
91 ]
92
93 test_t = 760233600 # assume broken POSIX counting of seconds
94 result = time2isoz(test_t)
95 expected = "1994-02-03 00:00:00Z"
Ezio Melottib3aedd42010-11-20 19:04:17 +000096 self.assertEqual(result, expected,
97 "%s => '%s' (%s)" % (test_t, result, expected))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +000098
99 for s in tests:
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200100 self.assertEqual(http2time(s), test_t, s)
101 self.assertEqual(http2time(s.lower()), test_t, s.lower())
102 self.assertEqual(http2time(s.upper()), test_t, s.upper())
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000103
104 def test_http2time_garbage(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000105 for test in [
106 '',
107 'Garbage',
108 'Mandag 16. September 1996',
109 '01-00-1980',
110 '01-13-1980',
111 '00-01-1980',
112 '32-01-1980',
113 '01-01-1980 25:00:00',
114 '01-01-1980 00:61:00',
115 '01-01-1980 00:00:62',
Berker Peksag20be53e2016-03-14 05:48:02 +0200116 '08-Oct-3697739',
117 '08-01-3697739',
118 '09 Feb 19942632 22:23:32 GMT',
119 'Wed, 09 Feb 1994834 22:23:32 GMT',
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000120 ]:
Ezio Melotti1d237e52013-08-10 18:20:09 +0300121 self.assertIsNone(http2time(test),
122 "http2time(%s) is not None\n"
123 "http2time(test) %s" % (test, http2time(test)))
124
125 def test_iso2time(self):
126 def parse_date(text):
127 return time.gmtime(iso2time(text))[:6]
128
129 # ISO 8601 compact format
130 self.assertEqual(parse_date("19940203T141529Z"),
131 (1994, 2, 3, 14, 15, 29))
132
133 # ISO 8601 with time behind UTC
134 self.assertEqual(parse_date("1994-02-03 07:15:29 -0700"),
135 (1994, 2, 3, 14, 15, 29))
136
137 # ISO 8601 with time ahead of UTC
138 self.assertEqual(parse_date("1994-02-03 19:45:29 +0530"),
139 (1994, 2, 3, 14, 15, 29))
140
141 def test_iso2time_formats(self):
142 # test iso2time for supported dates.
143 tests = [
144 '1994-02-03 00:00:00 -0000', # ISO 8601 format
145 '1994-02-03 00:00:00 +0000', # ISO 8601 format
146 '1994-02-03 00:00:00', # zone is optional
147 '1994-02-03', # only date
148 '1994-02-03T00:00:00', # Use T as separator
149 '19940203', # only date
150 '1994-02-02 24:00:00', # using hour-24 yesterday date
151 '19940203T000000Z', # ISO 8601 compact format
152
153 # A few tests with extra space at various places
154 ' 1994-02-03 ',
155 ' 1994-02-03T00:00:00 ',
156 ]
157
158 test_t = 760233600 # assume broken POSIX counting of seconds
159 for s in tests:
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200160 self.assertEqual(iso2time(s), test_t, s)
161 self.assertEqual(iso2time(s.lower()), test_t, s.lower())
162 self.assertEqual(iso2time(s.upper()), test_t, s.upper())
Ezio Melotti1d237e52013-08-10 18:20:09 +0300163
164 def test_iso2time_garbage(self):
165 for test in [
166 '',
167 'Garbage',
168 'Thursday, 03-Feb-94 00:00:00 GMT',
169 '1980-00-01',
170 '1980-13-01',
171 '1980-01-00',
172 '1980-01-32',
173 '1980-01-01 25:00:00',
174 '1980-01-01 00:61:00',
175 '01-01-1980 00:00:62',
176 '01-01-1980T00:00:62',
177 '19800101T250000Z'
178 '1980-01-01 00:00:00 -2500',
179 ]:
180 self.assertIsNone(iso2time(test),
181 "iso2time(%s) is not None\n"
182 "iso2time(test) %s" % (test, iso2time(test)))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000183
184
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000185class HeaderTests(unittest.TestCase):
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000186
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000187 def test_parse_ns_headers(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000188 # quotes should be stripped
Guido van Rossume2a383d2007-01-15 16:59:06 +0000189 expected = [[('foo', 'bar'), ('expires', 2209069412), ('version', '0')]]
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000190 for hdr in [
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000191 'foo=bar; expires=01 Jan 2040 22:23:32 GMT',
192 'foo=bar; expires="01 Jan 2040 22:23:32 GMT"',
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000193 ]:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000194 self.assertEqual(parse_ns_headers([hdr]), expected)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000195
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000196 def test_parse_ns_headers_version(self):
197
198 # quotes should be stripped
199 expected = [[('foo', 'bar'), ('version', '1')]]
200 for hdr in [
201 'foo=bar; version="1"',
202 'foo=bar; Version="1"',
203 ]:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000204 self.assertEqual(parse_ns_headers([hdr]), expected)
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000205
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000206 def test_parse_ns_headers_special_names(self):
207 # names such as 'expires' are not special in first name=value pair
208 # of Set-Cookie: header
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000209 # Cookie with name 'expires'
210 hdr = 'expires=01 Jan 2040 22:23:32 GMT'
211 expected = [[("expires", "01 Jan 2040 22:23:32 GMT"), ("version", "0")]]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000212 self.assertEqual(parse_ns_headers([hdr]), expected)
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000213
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000214 def test_join_header_words(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000215 joined = join_header_words([[("foo", None), ("bar", "baz")]])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000216 self.assertEqual(joined, "foo; bar=baz")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000217
Ezio Melottib3aedd42010-11-20 19:04:17 +0000218 self.assertEqual(join_header_words([[]]), "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000219
220 def test_split_header_words(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000221 tests = [
222 ("foo", [[("foo", None)]]),
223 ("foo=bar", [[("foo", "bar")]]),
224 (" foo ", [[("foo", None)]]),
225 (" foo= ", [[("foo", "")]]),
226 (" foo=", [[("foo", "")]]),
227 (" foo= ; ", [[("foo", "")]]),
228 (" foo= ; bar= baz ", [[("foo", ""), ("bar", "baz")]]),
229 ("foo=bar bar=baz", [[("foo", "bar"), ("bar", "baz")]]),
230 # doesn't really matter if this next fails, but it works ATM
231 ("foo= bar=baz", [[("foo", "bar=baz")]]),
232 ("foo=bar;bar=baz", [[("foo", "bar"), ("bar", "baz")]]),
233 ('foo bar baz', [[("foo", None), ("bar", None), ("baz", None)]]),
234 ("a, b, c", [[("a", None)], [("b", None)], [("c", None)]]),
235 (r'foo; bar=baz, spam=, foo="\,\;\"", bar= ',
236 [[("foo", None), ("bar", "baz")],
237 [("spam", "")], [("foo", ',;"')], [("bar", "")]]),
238 ]
239
240 for arg, expect in tests:
241 try:
242 result = split_header_words([arg])
243 except:
Guido van Rossum34d19282007-08-09 01:03:29 +0000244 import traceback, io
245 f = io.StringIO()
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000246 traceback.print_exc(None, f)
247 result = "(error -- traceback follows)\n\n%s" % f.getvalue()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000248 self.assertEqual(result, expect, """
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000249When parsing: '%s'
250Expected: '%s'
251Got: '%s'
252""" % (arg, expect, result))
253
254 def test_roundtrip(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000255 tests = [
256 ("foo", "foo"),
257 ("foo=bar", "foo=bar"),
258 (" foo ", "foo"),
259 ("foo=", 'foo=""'),
260 ("foo=bar bar=baz", "foo=bar; bar=baz"),
261 ("foo=bar;bar=baz", "foo=bar; bar=baz"),
262 ('foo bar baz', "foo; bar; baz"),
263 (r'foo="\"" bar="\\"', r'foo="\""; bar="\\"'),
264 ('foo,,,bar', 'foo, bar'),
265 ('foo=bar,bar=baz', 'foo=bar, bar=baz'),
266
267 ('text/html; charset=iso-8859-1',
268 'text/html; charset="iso-8859-1"'),
269
270 ('foo="bar"; port="80,81"; discard, bar=baz',
271 'foo=bar; port="80,81"; discard, bar=baz'),
272
273 (r'Basic realm="\"foo\\\\bar\""',
274 r'Basic; realm="\"foo\\\\bar\""')
275 ]
276
277 for arg, expect in tests:
278 input = split_header_words([arg])
279 res = join_header_words(input)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000280 self.assertEqual(res, expect, """
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000281When parsing: '%s'
282Expected: '%s'
283Got: '%s'
284Input was: '%s'
285""" % (arg, expect, res, input))
286
287
288class FakeResponse:
289 def __init__(self, headers=[], url=None):
290 """
291 headers: list of RFC822-style 'Key: value' strings
292 """
Barry Warsaw820c1202008-06-12 04:06:45 +0000293 import email
294 self._headers = email.message_from_string("\n".join(headers))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000295 self._url = url
296 def info(self): return self._headers
297
298def interact_2965(cookiejar, url, *set_cookie_hdrs):
299 return _interact(cookiejar, url, set_cookie_hdrs, "Set-Cookie2")
300
301def interact_netscape(cookiejar, url, *set_cookie_hdrs):
302 return _interact(cookiejar, url, set_cookie_hdrs, "Set-Cookie")
303
304def _interact(cookiejar, url, set_cookie_hdrs, hdr_name):
305 """Perform a single request / response cycle, returning Cookie: header."""
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000306 req = urllib.request.Request(url)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000307 cookiejar.add_cookie_header(req)
308 cookie_hdr = req.get_header("Cookie", "")
309 headers = []
310 for hdr in set_cookie_hdrs:
311 headers.append("%s: %s" % (hdr_name, hdr))
312 res = FakeResponse(headers, url)
313 cookiejar.extract_cookies(res, req)
314 return cookie_hdr
315
316
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000317class FileCookieJarTests(unittest.TestCase):
Martin v. Löwisc5574e82005-03-03 10:57:37 +0000318 def test_lwp_valueless_cookie(self):
319 # cookies with no value should be saved and loaded consistently
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000320 filename = test.support.TESTFN
Martin v. Löwisc5574e82005-03-03 10:57:37 +0000321 c = LWPCookieJar()
322 interact_netscape(c, "http://www.acme.com/", 'boo')
323 self.assertEqual(c._cookies["www.acme.com"]["/"]["boo"].value, None)
324 try:
325 c.save(filename, ignore_discard=True)
326 c = LWPCookieJar()
327 c.load(filename, ignore_discard=True)
328 finally:
329 try: os.unlink(filename)
330 except OSError: pass
331 self.assertEqual(c._cookies["www.acme.com"]["/"]["boo"].value, None)
332
Neal Norwitz3e7de592005-12-23 21:24:35 +0000333 def test_bad_magic(self):
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200334 # OSErrors (eg. file doesn't exist) are allowed to propagate
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000335 filename = test.support.TESTFN
Neal Norwitz3e7de592005-12-23 21:24:35 +0000336 for cookiejar_class in LWPCookieJar, MozillaCookieJar:
337 c = cookiejar_class()
338 try:
339 c.load(filename="for this test to work, a file with this "
340 "filename should not exist")
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200341 except OSError as exc:
342 # an OSError subclass (likely FileNotFoundError), but not
343 # LoadError
344 self.assertIsNot(exc.__class__, LoadError)
Neal Norwitz3e7de592005-12-23 21:24:35 +0000345 else:
Antoine Pitrou6b4883d2011-10-12 02:54:14 +0200346 self.fail("expected OSError for invalid filename")
Neal Norwitz3e7de592005-12-23 21:24:35 +0000347 # Invalid contents of cookies file (eg. bad magic string)
348 # causes a LoadError.
349 try:
Brett Cannon7f462fc2010-10-29 23:27:39 +0000350 with open(filename, "w") as f:
351 f.write("oops\n")
352 for cookiejar_class in LWPCookieJar, MozillaCookieJar:
353 c = cookiejar_class()
354 self.assertRaises(LoadError, c.load, filename)
Neal Norwitz3e7de592005-12-23 21:24:35 +0000355 finally:
356 try: os.unlink(filename)
357 except OSError: pass
Martin v. Löwisc5574e82005-03-03 10:57:37 +0000358
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000359class CookieTests(unittest.TestCase):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000360 # XXX
361 # Get rid of string comparisons where not actually testing str / repr.
362 # .clear() etc.
363 # IP addresses like 50 (single number, no dot) and domain-matching
364 # functions (and is_HDN)? See draft RFC 2965 errata.
365 # Strictness switches
366 # is_third_party()
367 # unverifiability / third-party blocking
368 # Netscape cookies work the same as RFC 2965 with regard to port.
369 # Set-Cookie with negative max age.
370 # If turn RFC 2965 handling off, Set-Cookie2 cookies should not clobber
371 # Set-Cookie cookies.
372 # Cookie2 should be sent if *any* cookies are not V1 (ie. V0 OR V2 etc.).
373 # Cookies (V1 and V0) with no expiry date should be set to be discarded.
374 # RFC 2965 Quoting:
375 # Should accept unquoted cookie-attribute values? check errata draft.
376 # Which are required on the way in and out?
377 # Should always return quoted cookie-attribute values?
378 # Proper testing of when RFC 2965 clobbers Netscape (waiting for errata).
379 # Path-match on return (same for V0 and V1).
380 # RFC 2965 acceptance and returning rules
381 # Set-Cookie2 without version attribute is rejected.
382
383 # Netscape peculiarities list from Ronald Tschalar.
384 # The first two still need tests, the rest are covered.
385## - Quoting: only quotes around the expires value are recognized as such
386## (and yes, some folks quote the expires value); quotes around any other
387## value are treated as part of the value.
388## - White space: white space around names and values is ignored
389## - Default path: if no path parameter is given, the path defaults to the
390## path in the request-uri up to, but not including, the last '/'. Note
391## that this is entirely different from what the spec says.
392## - Commas and other delimiters: Netscape just parses until the next ';'.
393## This means it will allow commas etc inside values (and yes, both
394## commas and equals are commonly appear in the cookie value). This also
395## means that if you fold multiple Set-Cookie header fields into one,
396## comma-separated list, it'll be a headache to parse (at least my head
Ezio Melotti85a86292013-08-17 16:57:41 +0300397## starts hurting every time I think of that code).
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000398## - Expires: You'll get all sorts of date formats in the expires,
Martin Pantereb995702016-07-28 01:11:04 +0000399## including empty expires attributes ("expires="). Be as flexible as you
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000400## can, and certainly don't expect the weekday to be there; if you can't
401## parse it, just ignore it and pretend it's a session cookie.
402## - Domain-matching: Netscape uses the 2-dot rule for _all_ domains, not
403## just the 7 special TLD's listed in their spec. And folks rely on
404## that...
405
406 def test_domain_return_ok(self):
407 # test optimization: .domain_return_ok() should filter out most
408 # domains in the CookieJar before we try to access them (because that
409 # may require disk access -- in particular, with MSIECookieJar)
410 # This is only a rough check for performance reasons, so it's not too
411 # critical as long as it's sufficiently liberal.
Georg Brandl24420152008-05-26 16:32:26 +0000412 pol = DefaultCookiePolicy()
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000413 for url, domain, ok in [
414 ("http://foo.bar.com/", "blah.com", False),
415 ("http://foo.bar.com/", "rhubarb.blah.com", False),
416 ("http://foo.bar.com/", "rhubarb.foo.bar.com", False),
417 ("http://foo.bar.com/", ".foo.bar.com", True),
418 ("http://foo.bar.com/", "foo.bar.com", True),
419 ("http://foo.bar.com/", ".bar.com", True),
420 ("http://foo.bar.com/", "com", True),
421 ("http://foo.com/", "rhubarb.foo.com", False),
422 ("http://foo.com/", ".foo.com", True),
423 ("http://foo.com/", "foo.com", True),
424 ("http://foo.com/", "com", True),
425 ("http://foo/", "rhubarb.foo", False),
426 ("http://foo/", ".foo", True),
427 ("http://foo/", "foo", True),
428 ("http://foo/", "foo.local", True),
429 ("http://foo/", ".local", True),
430 ]:
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000431 request = urllib.request.Request(url)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000432 r = pol.domain_return_ok(domain, request)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000433 if ok: self.assertTrue(r)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200434 else: self.assertFalse(r)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000435
436 def test_missing_value(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000437 # missing = sign in Cookie: header is regarded by Mozilla as a missing
Georg Brandl24420152008-05-26 16:32:26 +0000438 # name, and by http.cookiejar as a missing value
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000439 filename = test.support.TESTFN
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000440 c = MozillaCookieJar(filename)
441 interact_netscape(c, "http://www.acme.com/", 'eggs')
442 interact_netscape(c, "http://www.acme.com/", '"spam"; path=/foo/')
443 cookie = c._cookies["www.acme.com"]["/"]["eggs"]
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200444 self.assertIsNone(cookie.value)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000445 self.assertEqual(cookie.name, "eggs")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000446 cookie = c._cookies["www.acme.com"]['/foo/']['"spam"']
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200447 self.assertIsNone(cookie.value)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000448 self.assertEqual(cookie.name, '"spam"')
449 self.assertEqual(lwp_cookie_str(cookie), (
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000450 r'"spam"; path="/foo/"; domain="www.acme.com"; '
451 'path_spec; discard; version=0'))
452 old_str = repr(c)
453 c.save(ignore_expires=True, ignore_discard=True)
454 try:
455 c = MozillaCookieJar(filename)
456 c.revert(ignore_expires=True, ignore_discard=True)
457 finally:
458 os.unlink(c.filename)
459 # cookies unchanged apart from lost info re. whether path was specified
Ezio Melottib3aedd42010-11-20 19:04:17 +0000460 self.assertEqual(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000461 repr(c),
462 re.sub("path_specified=%s" % True, "path_specified=%s" % False,
463 old_str)
464 )
Ezio Melottib3aedd42010-11-20 19:04:17 +0000465 self.assertEqual(interact_netscape(c, "http://www.acme.com/foo/"),
466 '"spam"; eggs')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000467
Neal Norwitz71dad722005-12-23 21:43:48 +0000468 def test_rfc2109_handling(self):
469 # RFC 2109 cookies are handled as RFC 2965 or Netscape cookies,
470 # dependent on policy settings
Neal Norwitz71dad722005-12-23 21:43:48 +0000471 for rfc2109_as_netscape, rfc2965, version in [
472 # default according to rfc2965 if not explicitly specified
473 (None, False, 0),
474 (None, True, 1),
475 # explicit rfc2109_as_netscape
476 (False, False, None), # version None here means no cookie stored
477 (False, True, 1),
478 (True, False, 0),
479 (True, True, 0),
480 ]:
481 policy = DefaultCookiePolicy(
482 rfc2109_as_netscape=rfc2109_as_netscape,
483 rfc2965=rfc2965)
484 c = CookieJar(policy)
485 interact_netscape(c, "http://www.example.com/", "ni=ni; Version=1")
486 try:
487 cookie = c._cookies["www.example.com"]["/"]["ni"]
488 except KeyError:
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200489 self.assertIsNone(version) # didn't expect a stored cookie
Neal Norwitz71dad722005-12-23 21:43:48 +0000490 else:
491 self.assertEqual(cookie.version, version)
492 # 2965 cookies are unaffected
493 interact_2965(c, "http://www.example.com/",
494 "foo=bar; Version=1")
495 if rfc2965:
496 cookie2965 = c._cookies["www.example.com"]["/"]["foo"]
497 self.assertEqual(cookie2965.version, 1)
498
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000499 def test_ns_parser(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000500 c = CookieJar()
501 interact_netscape(c, "http://www.acme.com/",
502 'spam=eggs; DoMain=.acme.com; port; blArgh="feep"')
503 interact_netscape(c, "http://www.acme.com/", 'ni=ni; port=80,8080')
504 interact_netscape(c, "http://www.acme.com:80/", 'nini=ni')
505 interact_netscape(c, "http://www.acme.com:80/", 'foo=bar; expires=')
506 interact_netscape(c, "http://www.acme.com:80/", 'spam=eggs; '
507 'expires="Foo Bar 25 33:22:11 3022"')
Serhiy Storchaka577fc4e2015-03-13 09:05:01 +0200508 interact_netscape(c, 'http://www.acme.com/', 'fortytwo=')
509 interact_netscape(c, 'http://www.acme.com/', '=unladenswallow')
510 interact_netscape(c, 'http://www.acme.com/', 'holyhandgrenade')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000511
512 cookie = c._cookies[".acme.com"]["/"]["spam"]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000513 self.assertEqual(cookie.domain, ".acme.com")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000514 self.assertTrue(cookie.domain_specified)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000515 self.assertEqual(cookie.port, DEFAULT_HTTP_PORT)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200516 self.assertFalse(cookie.port_specified)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000517 # case is preserved
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200518 self.assertTrue(cookie.has_nonstandard_attr("blArgh"))
519 self.assertFalse(cookie.has_nonstandard_attr("blargh"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000520
521 cookie = c._cookies["www.acme.com"]["/"]["ni"]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000522 self.assertEqual(cookie.domain, "www.acme.com")
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200523 self.assertFalse(cookie.domain_specified)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000524 self.assertEqual(cookie.port, "80,8080")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000525 self.assertTrue(cookie.port_specified)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000526
527 cookie = c._cookies["www.acme.com"]["/"]["nini"]
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200528 self.assertIsNone(cookie.port)
529 self.assertFalse(cookie.port_specified)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000530
531 # invalid expires should not cause cookie to be dropped
532 foo = c._cookies["www.acme.com"]["/"]["foo"]
533 spam = c._cookies["www.acme.com"]["/"]["foo"]
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200534 self.assertIsNone(foo.expires)
535 self.assertIsNone(spam.expires)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000536
Serhiy Storchaka577fc4e2015-03-13 09:05:01 +0200537 cookie = c._cookies['www.acme.com']['/']['fortytwo']
538 self.assertIsNotNone(cookie.value)
539 self.assertEqual(cookie.value, '')
540
541 # there should be a distinction between a present but empty value
542 # (above) and a value that's entirely missing (below)
543
544 cookie = c._cookies['www.acme.com']['/']['holyhandgrenade']
545 self.assertIsNone(cookie.value)
546
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000547 def test_ns_parser_special_names(self):
548 # names such as 'expires' are not special in first name=value pair
549 # of Set-Cookie: header
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000550 c = CookieJar()
551 interact_netscape(c, "http://www.acme.com/", 'expires=eggs')
552 interact_netscape(c, "http://www.acme.com/", 'version=eggs; spam=eggs')
553
554 cookies = c._cookies["www.acme.com"]["/"]
Benjamin Peterson577473f2010-01-19 00:09:57 +0000555 self.assertIn('expires', cookies)
556 self.assertIn('version', cookies)
Martin v. Löwis4ea3ead2005-03-03 10:48:12 +0000557
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000558 def test_expires(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000559 # if expires is in future, keep cookie...
560 c = CookieJar()
561 future = time2netscape(time.time()+3600)
562 interact_netscape(c, "http://www.acme.com/", 'spam="bar"; expires=%s' %
563 future)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000564 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000565 now = time2netscape(time.time()-1)
566 # ... and if in past or present, discard it
567 interact_netscape(c, "http://www.acme.com/", 'foo="eggs"; expires=%s' %
568 now)
569 h = interact_netscape(c, "http://www.acme.com/")
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)
572 self.assertNotIn("foo", h)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000573
574 # max-age takes precedence over expires, and zero max-age is request to
575 # delete both new cookie and any old matching cookie
576 interact_netscape(c, "http://www.acme.com/", 'eggs="bar"; expires=%s' %
577 future)
578 interact_netscape(c, "http://www.acme.com/", 'bar="bar"; expires=%s' %
579 future)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000580 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000581 interact_netscape(c, "http://www.acme.com/", 'eggs="bar"; '
582 'expires=%s; max-age=0' % future)
583 interact_netscape(c, "http://www.acme.com/", 'bar="bar"; '
584 'max-age=0; expires=%s' % future)
585 h = interact_netscape(c, "http://www.acme.com/")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000586 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000587
588 # test expiry at end of session for cookies with no expires attribute
589 interact_netscape(c, "http://www.rhubarb.net/", 'whum="fizz"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000590 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000591 c.clear_session_cookies()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000592 self.assertEqual(len(c), 1)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000593 self.assertIn('spam="bar"', h)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000594
Robert Collinsa0e5d982015-08-04 10:06:29 +1200595 # test if fractional expiry is accepted
596 cookie = Cookie(0, "name", "value",
597 None, False, "www.python.org",
598 True, False, "/",
599 False, False, "1444312383.018307",
600 False, None, None,
601 {})
602 self.assertEqual(cookie.expires, 1444312383)
603
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000604 # XXX RFC 2965 expiry rules (some apply to V0 too)
605
606 def test_default_path(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000607 # RFC 2965
608 pol = DefaultCookiePolicy(rfc2965=True)
609
610 c = CookieJar(pol)
611 interact_2965(c, "http://www.acme.com/", 'spam="bar"; Version="1"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000612 self.assertIn("/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000613
614 c = CookieJar(pol)
615 interact_2965(c, "http://www.acme.com/blah", 'eggs="bar"; Version="1"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000616 self.assertIn("/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000617
618 c = CookieJar(pol)
619 interact_2965(c, "http://www.acme.com/blah/rhubarb",
620 'eggs="bar"; Version="1"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000621 self.assertIn("/blah/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000622
623 c = CookieJar(pol)
624 interact_2965(c, "http://www.acme.com/blah/rhubarb/",
625 'eggs="bar"; Version="1"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000626 self.assertIn("/blah/rhubarb/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000627
628 # Netscape
629
630 c = CookieJar()
631 interact_netscape(c, "http://www.acme.com/", 'spam="bar"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000632 self.assertIn("/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000633
634 c = CookieJar()
635 interact_netscape(c, "http://www.acme.com/blah", 'eggs="bar"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000636 self.assertIn("/", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000637
638 c = CookieJar()
639 interact_netscape(c, "http://www.acme.com/blah/rhubarb", 'eggs="bar"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000640 self.assertIn("/blah", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000641
642 c = CookieJar()
643 interact_netscape(c, "http://www.acme.com/blah/rhubarb/", 'eggs="bar"')
Benjamin Peterson577473f2010-01-19 00:09:57 +0000644 self.assertIn("/blah/rhubarb", c._cookies["www.acme.com"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000645
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000646 def test_default_path_with_query(self):
647 cj = CookieJar()
648 uri = "http://example.com/?spam/eggs"
649 value = 'eggs="bar"'
650 interact_netscape(cj, uri, value)
651 # Default path does not include query, so is "/", not "/?spam".
652 self.assertIn("/", cj._cookies["example.com"])
653 # Cookie is sent back to the same URI.
Ezio Melottib3aedd42010-11-20 19:04:17 +0000654 self.assertEqual(interact_netscape(cj, uri), value)
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000655
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000656 def test_escape_path(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000657 cases = [
658 # quoted safe
659 ("/foo%2f/bar", "/foo%2F/bar"),
660 ("/foo%2F/bar", "/foo%2F/bar"),
661 # quoted %
662 ("/foo%%/bar", "/foo%%/bar"),
663 # quoted unsafe
664 ("/fo%19o/bar", "/fo%19o/bar"),
665 ("/fo%7do/bar", "/fo%7Do/bar"),
666 # unquoted safe
667 ("/foo/bar&", "/foo/bar&"),
668 ("/foo//bar", "/foo//bar"),
669 ("\176/foo/bar", "\176/foo/bar"),
670 # unquoted unsafe
671 ("/foo\031/bar", "/foo%19/bar"),
672 ("/\175foo/bar", "/%7Dfoo/bar"),
Guido van Rossum52dbbb92008-08-18 21:44:30 +0000673 # unicode, latin-1 range
674 ("/foo/bar\u00fc", "/foo/bar%C3%BC"), # UTF-8 encoded
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000675 # unicode
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000676 ("/foo/bar\uabcd", "/foo/bar%EA%AF%8D"), # UTF-8 encoded
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000677 ]
678 for arg, result in cases:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000679 self.assertEqual(escape_path(arg), result)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000680
681 def test_request_path(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000682 # with parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000683 req = urllib.request.Request(
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000684 "http://www.example.com/rheum/rhaponticum;"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000685 "foo=bar;sing=song?apples=pears&spam=eggs#ni")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000686 self.assertEqual(request_path(req),
687 "/rheum/rhaponticum;foo=bar;sing=song")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000688 # without parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000689 req = urllib.request.Request(
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +0000690 "http://www.example.com/rheum/rhaponticum?"
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000691 "apples=pears&spam=eggs#ni")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000692 self.assertEqual(request_path(req), "/rheum/rhaponticum")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000693 # missing final slash
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000694 req = urllib.request.Request("http://www.example.com")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000695 self.assertEqual(request_path(req), "/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000696
697 def test_request_port(self):
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000698 req = urllib.request.Request("http://www.acme.com:1234/",
699 headers={"Host": "www.acme.com:4321"})
Ezio Melottib3aedd42010-11-20 19:04:17 +0000700 self.assertEqual(request_port(req), "1234")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000701 req = urllib.request.Request("http://www.acme.com/",
702 headers={"Host": "www.acme.com:4321"})
Ezio Melottib3aedd42010-11-20 19:04:17 +0000703 self.assertEqual(request_port(req), DEFAULT_HTTP_PORT)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000704
705 def test_request_host(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000706 # this request is illegal (RFC2616, 14.2.3)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000707 req = urllib.request.Request("http://1.1.1.1/",
708 headers={"Host": "www.acme.com:80"})
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000709 # libwww-perl wants this response, but that seems wrong (RFC 2616,
710 # section 5.2, point 1., and RFC 2965 section 1, paragraph 3)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000711 #self.assertEqual(request_host(req), "www.acme.com")
712 self.assertEqual(request_host(req), "1.1.1.1")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000713 req = urllib.request.Request("http://www.acme.com/",
714 headers={"Host": "irrelevant.com"})
Ezio Melottib3aedd42010-11-20 19:04:17 +0000715 self.assertEqual(request_host(req), "www.acme.com")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000716 # port shouldn't be in request-host
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000717 req = urllib.request.Request("http://www.acme.com:2345/resource.html",
718 headers={"Host": "www.acme.com:5432"})
Ezio Melottib3aedd42010-11-20 19:04:17 +0000719 self.assertEqual(request_host(req), "www.acme.com")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000720
721 def test_is_HDN(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000722 self.assertTrue(is_HDN("foo.bar.com"))
723 self.assertTrue(is_HDN("1foo2.3bar4.5com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200724 self.assertFalse(is_HDN("192.168.1.1"))
725 self.assertFalse(is_HDN(""))
726 self.assertFalse(is_HDN("."))
727 self.assertFalse(is_HDN(".foo.bar.com"))
728 self.assertFalse(is_HDN("..foo"))
729 self.assertFalse(is_HDN("foo."))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000730
731 def test_reach(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000732 self.assertEqual(reach("www.acme.com"), ".acme.com")
733 self.assertEqual(reach("acme.com"), "acme.com")
734 self.assertEqual(reach("acme.local"), ".local")
735 self.assertEqual(reach(".local"), ".local")
736 self.assertEqual(reach(".com"), ".com")
737 self.assertEqual(reach("."), ".")
738 self.assertEqual(reach(""), "")
739 self.assertEqual(reach("192.168.0.1"), "192.168.0.1")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000740
741 def test_domain_match(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000742 self.assertTrue(domain_match("192.168.1.1", "192.168.1.1"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200743 self.assertFalse(domain_match("192.168.1.1", ".168.1.1"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000744 self.assertTrue(domain_match("x.y.com", "x.Y.com"))
745 self.assertTrue(domain_match("x.y.com", ".Y.com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200746 self.assertFalse(domain_match("x.y.com", "Y.com"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000747 self.assertTrue(domain_match("a.b.c.com", ".c.com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200748 self.assertFalse(domain_match(".c.com", "a.b.c.com"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000749 self.assertTrue(domain_match("example.local", ".local"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200750 self.assertFalse(domain_match("blah.blah", ""))
751 self.assertFalse(domain_match("", ".rhubarb.rhubarb"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000752 self.assertTrue(domain_match("", ""))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000753
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000754 self.assertTrue(user_domain_match("acme.com", "acme.com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200755 self.assertFalse(user_domain_match("acme.com", ".acme.com"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000756 self.assertTrue(user_domain_match("rhubarb.acme.com", ".acme.com"))
757 self.assertTrue(user_domain_match("www.rhubarb.acme.com", ".acme.com"))
758 self.assertTrue(user_domain_match("x.y.com", "x.Y.com"))
759 self.assertTrue(user_domain_match("x.y.com", ".Y.com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200760 self.assertFalse(user_domain_match("x.y.com", "Y.com"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000761 self.assertTrue(user_domain_match("y.com", "Y.com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200762 self.assertFalse(user_domain_match(".y.com", "Y.com"))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000763 self.assertTrue(user_domain_match(".y.com", ".Y.com"))
764 self.assertTrue(user_domain_match("x.y.com", ".com"))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200765 self.assertFalse(user_domain_match("x.y.com", "com"))
766 self.assertFalse(user_domain_match("x.y.com", "m"))
767 self.assertFalse(user_domain_match("x.y.com", ".m"))
768 self.assertFalse(user_domain_match("x.y.com", ""))
769 self.assertFalse(user_domain_match("x.y.com", "."))
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000770 self.assertTrue(user_domain_match("192.168.1.1", "192.168.1.1"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000771 # not both HDNs, so must string-compare equal to match
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200772 self.assertFalse(user_domain_match("192.168.1.1", ".168.1.1"))
773 self.assertFalse(user_domain_match("192.168.1.1", "."))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000774 # empty string is a special case
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200775 self.assertFalse(user_domain_match("192.168.1.1", ""))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000776
777 def test_wrong_domain(self):
778 # Cookies whose effective request-host name does not domain-match the
779 # domain are rejected.
780
781 # XXX far from complete
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000782 c = CookieJar()
783 interact_2965(c, "http://www.nasty.com/",
784 'foo=bar; domain=friendly.org; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000785 self.assertEqual(len(c), 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000786
Thomas Wouters477c8d52006-05-27 19:21:47 +0000787 def test_strict_domain(self):
788 # Cookies whose domain is a country-code tld like .co.uk should
789 # not be set if CookiePolicy.strict_domain is true.
Thomas Wouters477c8d52006-05-27 19:21:47 +0000790 cp = DefaultCookiePolicy(strict_domain=True)
791 cj = CookieJar(policy=cp)
792 interact_netscape(cj, "http://example.co.uk/", 'no=problemo')
793 interact_netscape(cj, "http://example.co.uk/",
794 'okey=dokey; Domain=.example.co.uk')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000795 self.assertEqual(len(cj), 2)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000796 for pseudo_tld in [".co.uk", ".org.za", ".tx.us", ".name.us"]:
797 interact_netscape(cj, "http://example.%s/" % pseudo_tld,
798 'spam=eggs; Domain=.co.uk')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000799 self.assertEqual(len(cj), 2)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000800
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000801 def test_two_component_domain_ns(self):
802 # Netscape: .www.bar.com, www.bar.com, .bar.com, bar.com, no domain
803 # should all get accepted, as should .acme.com, acme.com and no domain
804 # for 2-component domains like acme.com.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000805 c = CookieJar()
806
807 # two-component V0 domain is OK
808 interact_netscape(c, "http://foo.net/", 'ns=bar')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000809 self.assertEqual(len(c), 1)
810 self.assertEqual(c._cookies["foo.net"]["/"]["ns"].value, "bar")
811 self.assertEqual(interact_netscape(c, "http://foo.net/"), "ns=bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000812 # *will* be returned to any other domain (unlike RFC 2965)...
Ezio Melottib3aedd42010-11-20 19:04:17 +0000813 self.assertEqual(interact_netscape(c, "http://www.foo.net/"),
814 "ns=bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000815 # ...unless requested otherwise
816 pol = DefaultCookiePolicy(
817 strict_ns_domain=DefaultCookiePolicy.DomainStrictNonDomain)
818 c.set_policy(pol)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000819 self.assertEqual(interact_netscape(c, "http://www.foo.net/"), "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000820
821 # unlike RFC 2965, even explicit two-component domain is OK,
822 # because .foo.net matches foo.net
823 interact_netscape(c, "http://foo.net/foo/",
824 'spam1=eggs; domain=foo.net')
825 # even if starts with a dot -- in NS rules, .foo.net matches foo.net!
826 interact_netscape(c, "http://foo.net/foo/bar/",
827 'spam2=eggs; domain=.foo.net')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000828 self.assertEqual(len(c), 3)
829 self.assertEqual(c._cookies[".foo.net"]["/foo"]["spam1"].value,
830 "eggs")
831 self.assertEqual(c._cookies[".foo.net"]["/foo/bar"]["spam2"].value,
832 "eggs")
833 self.assertEqual(interact_netscape(c, "http://foo.net/foo/bar/"),
834 "spam2=eggs; spam1=eggs; ns=bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000835
836 # top-level domain is too general
837 interact_netscape(c, "http://foo.net/", 'nini="ni"; domain=.net')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000838 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000839
840## # Netscape protocol doesn't allow non-special top level domains (such
841## # as co.uk) in the domain attribute unless there are at least three
842## # dots in it.
843 # Oh yes it does! Real implementations don't check this, and real
844 # cookies (of course) rely on that behaviour.
845 interact_netscape(c, "http://foo.co.uk", 'nasty=trick; domain=.co.uk')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000846## self.assertEqual(len(c), 2)
847 self.assertEqual(len(c), 4)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000848
849 def test_two_component_domain_rfc2965(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000850 pol = DefaultCookiePolicy(rfc2965=True)
851 c = CookieJar(pol)
852
853 # two-component V1 domain is OK
854 interact_2965(c, "http://foo.net/", 'foo=bar; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000855 self.assertEqual(len(c), 1)
856 self.assertEqual(c._cookies["foo.net"]["/"]["foo"].value, "bar")
857 self.assertEqual(interact_2965(c, "http://foo.net/"),
858 "$Version=1; foo=bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000859 # won't be returned to any other domain (because domain was implied)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000860 self.assertEqual(interact_2965(c, "http://www.foo.net/"), "")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000861
862 # unless domain is given explicitly, because then it must be
863 # rewritten to start with a dot: foo.net --> .foo.net, which does
864 # not domain-match foo.net
865 interact_2965(c, "http://foo.net/foo",
866 'spam=eggs; domain=foo.net; path=/foo; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000867 self.assertEqual(len(c), 1)
868 self.assertEqual(interact_2965(c, "http://foo.net/foo"),
869 "$Version=1; foo=bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000870
871 # explicit foo.net from three-component domain www.foo.net *does* get
872 # set, because .foo.net domain-matches .foo.net
873 interact_2965(c, "http://www.foo.net/foo/",
874 'spam=eggs; domain=foo.net; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000875 self.assertEqual(c._cookies[".foo.net"]["/foo/"]["spam"].value,
876 "eggs")
877 self.assertEqual(len(c), 2)
878 self.assertEqual(interact_2965(c, "http://foo.net/foo/"),
879 "$Version=1; foo=bar")
880 self.assertEqual(interact_2965(c, "http://www.foo.net/foo/"),
881 '$Version=1; spam=eggs; $Domain="foo.net"')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000882
883 # top-level domain is too general
884 interact_2965(c, "http://foo.net/",
885 'ni="ni"; domain=".net"; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000886 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000887
888 # RFC 2965 doesn't require blocking this
889 interact_2965(c, "http://foo.co.uk/",
890 'nasty=trick; domain=.co.uk; Version="1"')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000891 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000892
893 def test_domain_allow(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000894 c = CookieJar(policy=DefaultCookiePolicy(
895 blocked_domains=["acme.com"],
896 allowed_domains=["www.acme.com"]))
897
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000898 req = urllib.request.Request("http://acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000899 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
900 res = FakeResponse(headers, "http://acme.com/")
901 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000902 self.assertEqual(len(c), 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000903
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000904 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000905 res = FakeResponse(headers, "http://www.acme.com/")
906 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000907 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000908
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000909 req = urllib.request.Request("http://www.coyote.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000910 res = FakeResponse(headers, "http://www.coyote.com/")
911 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000912 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000913
914 # set a cookie with non-allowed domain...
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000915 req = urllib.request.Request("http://www.coyote.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000916 res = FakeResponse(headers, "http://www.coyote.com/")
917 cookies = c.make_cookies(res, req)
918 c.set_cookie(cookies[0])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000919 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000920 # ... and check is doesn't get returned
921 c.add_cookie_header(req)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200922 self.assertFalse(req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000923
924 def test_domain_block(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000925 pol = DefaultCookiePolicy(
926 rfc2965=True, blocked_domains=[".acme.com"])
927 c = CookieJar(policy=pol)
928 headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
929
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000930 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000931 res = FakeResponse(headers, "http://www.acme.com/")
932 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000933 self.assertEqual(len(c), 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000934
935 p = pol.set_blocked_domains(["acme.com"])
936 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000937 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000938
939 c.clear()
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000940 req = urllib.request.Request("http://www.roadrunner.net/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000941 res = FakeResponse(headers, "http://www.roadrunner.net/")
942 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000943 self.assertEqual(len(c), 1)
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000944 req = urllib.request.Request("http://www.roadrunner.net/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000945 c.add_cookie_header(req)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200946 self.assertTrue(req.has_header("Cookie"))
947 self.assertTrue(req.has_header("Cookie2"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000948
949 c.clear()
950 pol.set_blocked_domains([".acme.com"])
951 c.extract_cookies(res, req)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000952 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000953
954 # set a cookie with blocked domain...
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000955 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000956 res = FakeResponse(headers, "http://www.acme.com/")
957 cookies = c.make_cookies(res, req)
958 c.set_cookie(cookies[0])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000959 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000960 # ... and check is doesn't get returned
961 c.add_cookie_header(req)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200962 self.assertFalse(req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000963
964 def test_secure(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000965 for ns in True, False:
966 for whitespace in " ", "":
967 c = CookieJar()
968 if ns:
969 pol = DefaultCookiePolicy(rfc2965=False)
970 int = interact_netscape
971 vs = ""
972 else:
973 pol = DefaultCookiePolicy(rfc2965=True)
974 int = interact_2965
975 vs = "; Version=1"
976 c.set_policy(pol)
977 url = "http://www.acme.com/"
978 int(c, url, "foo1=bar%s%s" % (vs, whitespace))
979 int(c, url, "foo2=bar%s; secure%s" % (vs, whitespace))
Serhiy Storchaka9d282f62013-11-17 13:45:02 +0200980 self.assertFalse(
981 c._cookies["www.acme.com"]["/"]["foo1"].secure,
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000982 "non-secure cookie registered secure")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000983 self.assertTrue(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000984 c._cookies["www.acme.com"]["/"]["foo2"].secure,
985 "secure cookie registered non-secure")
986
987 def test_quote_cookie_value(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000988 c = CookieJar(policy=DefaultCookiePolicy(rfc2965=True))
989 interact_2965(c, "http://www.acme.com/", r'foo=\b"a"r; Version=1')
990 h = interact_2965(c, "http://www.acme.com/")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000991 self.assertEqual(h, r'$Version=1; foo=\\b\"a\"r')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000992
993 def test_missing_final_slash(self):
994 # Missing slash from request URL's abs_path should be assumed present.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +0000995 url = "http://www.acme.com"
996 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
997 interact_2965(c, url, "foo=bar; Version=1")
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000998 req = urllib.request.Request(url)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000999 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001000 c.add_cookie_header(req)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001001 self.assertTrue(req.has_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001002
1003 def test_domain_mirror(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001004 pol = DefaultCookiePolicy(rfc2965=True)
1005
1006 c = CookieJar(pol)
1007 url = "http://foo.bar.com/"
1008 interact_2965(c, url, "spam=eggs; Version=1")
1009 h = interact_2965(c, url)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001010 self.assertNotIn("Domain", h,
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001011 "absent domain returned with domain present")
1012
1013 c = CookieJar(pol)
1014 url = "http://foo.bar.com/"
1015 interact_2965(c, url, 'spam=eggs; Version=1; Domain=.bar.com')
1016 h = interact_2965(c, url)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001017 self.assertIn('$Domain=".bar.com"', h, "domain not returned")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001018
1019 c = CookieJar(pol)
1020 url = "http://foo.bar.com/"
1021 # note missing initial dot in Domain
1022 interact_2965(c, url, 'spam=eggs; Version=1; Domain=bar.com')
1023 h = interact_2965(c, url)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001024 self.assertIn('$Domain="bar.com"', h, "domain not returned")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001025
1026 def test_path_mirror(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001027 pol = DefaultCookiePolicy(rfc2965=True)
1028
1029 c = CookieJar(pol)
1030 url = "http://foo.bar.com/"
1031 interact_2965(c, url, "spam=eggs; Version=1")
1032 h = interact_2965(c, url)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001033 self.assertNotIn("Path", h, "absent path returned with path present")
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; Path=/')
1038 h = interact_2965(c, url)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001039 self.assertIn('$Path="/"', h, "path not returned")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001040
1041 def test_port_mirror(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001042 pol = DefaultCookiePolicy(rfc2965=True)
1043
1044 c = CookieJar(pol)
1045 url = "http://foo.bar.com/"
1046 interact_2965(c, url, "spam=eggs; Version=1")
1047 h = interact_2965(c, url)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001048 self.assertNotIn("Port", h, "absent port returned with port present")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001049
1050 c = CookieJar(pol)
1051 url = "http://foo.bar.com/"
1052 interact_2965(c, url, "spam=eggs; Version=1; Port")
1053 h = interact_2965(c, url)
R David Murray44b548d2016-09-08 13:59:53 -04001054 self.assertRegex(h, r"\$Port([^=]|$)",
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001055 "port with no value not returned with no value")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001056
1057 c = CookieJar(pol)
1058 url = "http://foo.bar.com/"
1059 interact_2965(c, url, 'spam=eggs; Version=1; Port="80"')
1060 h = interact_2965(c, url)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001061 self.assertIn('$Port="80"', h,
1062 "port with single value not returned with single value")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001063
1064 c = CookieJar(pol)
1065 url = "http://foo.bar.com/"
1066 interact_2965(c, url, 'spam=eggs; Version=1; Port="80,8080"')
1067 h = interact_2965(c, url)
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001068 self.assertIn('$Port="80,8080"', h,
1069 "port with multiple values not returned with multiple "
1070 "values")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001071
1072 def test_no_return_comment(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001073 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1074 url = "http://foo.bar.com/"
1075 interact_2965(c, url, 'spam=eggs; Version=1; '
1076 'Comment="does anybody read these?"; '
1077 'CommentURL="http://foo.bar.net/comment.html"')
1078 h = interact_2965(c, url)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001079 self.assertNotIn("Comment", h,
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001080 "Comment or CommentURL cookie-attributes returned to server")
1081
1082 def test_Cookie_iterator(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001083 cs = CookieJar(DefaultCookiePolicy(rfc2965=True))
1084 # add some random cookies
1085 interact_2965(cs, "http://blah.spam.org/", 'foo=eggs; Version=1; '
1086 'Comment="does anybody read these?"; '
1087 'CommentURL="http://foo.bar.net/comment.html"')
1088 interact_netscape(cs, "http://www.acme.com/blah/", "spam=bar; secure")
1089 interact_2965(cs, "http://www.acme.com/blah/",
1090 "foo=bar; secure; Version=1")
1091 interact_2965(cs, "http://www.acme.com/blah/",
1092 "foo=bar; path=/; Version=1")
1093 interact_2965(cs, "http://www.sol.no",
1094 r'bang=wallop; version=1; domain=".sol.no"; '
1095 r'port="90,100, 80,8080"; '
1096 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "')
1097
1098 versions = [1, 1, 1, 0, 1]
1099 names = ["bang", "foo", "foo", "spam", "foo"]
1100 domains = [".sol.no", "blah.spam.org", "www.acme.com",
1101 "www.acme.com", "www.acme.com"]
1102 paths = ["/", "/", "/", "/blah", "/blah/"]
1103
1104 for i in range(4):
1105 i = 0
1106 for c in cs:
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001107 self.assertIsInstance(c, Cookie)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001108 self.assertEqual(c.version, versions[i])
1109 self.assertEqual(c.name, names[i])
1110 self.assertEqual(c.domain, domains[i])
1111 self.assertEqual(c.path, paths[i])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001112 i = i + 1
1113
1114 def test_parse_ns_headers(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001115 # missing domain value (invalid cookie)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001116 self.assertEqual(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001117 parse_ns_headers(["foo=bar; path=/; domain"]),
1118 [[("foo", "bar"),
1119 ("path", "/"), ("domain", None), ("version", "0")]]
1120 )
1121 # invalid expires value
Ezio Melottib3aedd42010-11-20 19:04:17 +00001122 self.assertEqual(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001123 parse_ns_headers(["foo=bar; expires=Foo Bar 12 33:22:11 2000"]),
1124 [[("foo", "bar"), ("expires", None), ("version", "0")]]
1125 )
1126 # missing cookie value (valid cookie)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001127 self.assertEqual(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001128 parse_ns_headers(["foo"]),
1129 [[("foo", None), ("version", "0")]]
1130 )
Serhiy Storchaka577fc4e2015-03-13 09:05:01 +02001131 # missing cookie values for parsed attributes
1132 self.assertEqual(
1133 parse_ns_headers(['foo=bar; expires']),
1134 [[('foo', 'bar'), ('expires', None), ('version', '0')]])
1135 self.assertEqual(
1136 parse_ns_headers(['foo=bar; version']),
1137 [[('foo', 'bar'), ('version', None)]])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001138 # shouldn't add version if header is empty
Ezio Melottib3aedd42010-11-20 19:04:17 +00001139 self.assertEqual(parse_ns_headers([""]), [])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001140
1141 def test_bad_cookie_header(self):
1142
1143 def cookiejar_from_cookie_headers(headers):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001144 c = CookieJar()
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001145 req = urllib.request.Request("http://www.example.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001146 r = FakeResponse(headers, "http://www.example.com/")
1147 c.extract_cookies(r, req)
1148 return c
1149
Serhiy Storchaka577fc4e2015-03-13 09:05:01 +02001150 future = time2netscape(time.time()+3600)
1151
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001152 # none of these bad headers should cause an exception to be raised
1153 for headers in [
1154 ["Set-Cookie: "], # actually, nothing wrong with this
1155 ["Set-Cookie2: "], # ditto
1156 # missing domain value
1157 ["Set-Cookie2: a=foo; path=/; Version=1; domain"],
1158 # bad max-age
1159 ["Set-Cookie: b=foo; max-age=oops"],
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +00001160 # bad version
1161 ["Set-Cookie: b=foo; version=spam"],
Serhiy Storchaka577fc4e2015-03-13 09:05:01 +02001162 ["Set-Cookie:; Expires=%s" % future],
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001163 ]:
1164 c = cookiejar_from_cookie_headers(headers)
1165 # these bad cookies shouldn't be set
Ezio Melottib3aedd42010-11-20 19:04:17 +00001166 self.assertEqual(len(c), 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001167
1168 # cookie with invalid expires is treated as session cookie
1169 headers = ["Set-Cookie: c=foo; expires=Foo Bar 12 33:22:11 2000"]
1170 c = cookiejar_from_cookie_headers(headers)
1171 cookie = c._cookies["www.example.com"]["/"]["c"]
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001172 self.assertIsNone(cookie.expires)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001173
1174
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +00001175class LWPCookieTests(unittest.TestCase):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001176 # Tests taken from libwww-perl, with a few modifications and additions.
1177
1178 def test_netscape_example_1(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001179 #-------------------------------------------------------------------
1180 # First we check that it works for the original example at
1181 # http://www.netscape.com/newsref/std/cookie_spec.html
1182
1183 # Client requests a document, and receives in the response:
1184 #
1185 # Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
1186 #
1187 # When client requests a URL in path "/" on this server, it sends:
1188 #
1189 # Cookie: CUSTOMER=WILE_E_COYOTE
1190 #
1191 # Client requests a document, and receives in the response:
1192 #
1193 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
1194 #
1195 # When client requests a URL in path "/" on this server, it sends:
1196 #
1197 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
1198 #
1199 # Client receives:
1200 #
1201 # Set-Cookie: SHIPPING=FEDEX; path=/fo
1202 #
1203 # When client requests a URL in path "/" on this server, it sends:
1204 #
1205 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
1206 #
1207 # When client requests a URL in path "/foo" on this server, it sends:
1208 #
1209 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX
1210 #
1211 # The last Cookie is buggy, because both specifications say that the
1212 # most specific cookie must be sent first. SHIPPING=FEDEX is the
1213 # most specific and should thus be first.
1214
1215 year_plus_one = time.localtime()[0] + 1
1216
1217 headers = []
1218
1219 c = CookieJar(DefaultCookiePolicy(rfc2965 = True))
1220
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001221 #req = urllib.request.Request("http://1.1.1.1/",
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001222 # headers={"Host": "www.acme.com:80"})
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001223 req = urllib.request.Request("http://www.acme.com:80/",
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001224 headers={"Host": "www.acme.com:80"})
1225
1226 headers.append(
1227 "Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/ ; "
1228 "expires=Wednesday, 09-Nov-%d 23:12:40 GMT" % year_plus_one)
1229 res = FakeResponse(headers, "http://www.acme.com/")
1230 c.extract_cookies(res, req)
1231
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001232 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001233 c.add_cookie_header(req)
1234
1235 self.assertEqual(req.get_header("Cookie"), "CUSTOMER=WILE_E_COYOTE")
1236 self.assertEqual(req.get_header("Cookie2"), '$Version="1"')
1237
1238 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/")
1239 res = FakeResponse(headers, "http://www.acme.com/")
1240 c.extract_cookies(res, req)
1241
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001242 req = urllib.request.Request("http://www.acme.com/foo/bar")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001243 c.add_cookie_header(req)
1244
1245 h = req.get_header("Cookie")
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001246 self.assertIn("PART_NUMBER=ROCKET_LAUNCHER_0001", h)
1247 self.assertIn("CUSTOMER=WILE_E_COYOTE", h)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001248
1249 headers.append('Set-Cookie: SHIPPING=FEDEX; path=/foo')
1250 res = FakeResponse(headers, "http://www.acme.com")
1251 c.extract_cookies(res, req)
1252
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001253 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001254 c.add_cookie_header(req)
1255
1256 h = req.get_header("Cookie")
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001257 self.assertIn("PART_NUMBER=ROCKET_LAUNCHER_0001", h)
1258 self.assertIn("CUSTOMER=WILE_E_COYOTE", h)
1259 self.assertNotIn("SHIPPING=FEDEX", h)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001260
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001261 req = urllib.request.Request("http://www.acme.com/foo/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001262 c.add_cookie_header(req)
1263
1264 h = req.get_header("Cookie")
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001265 self.assertIn("PART_NUMBER=ROCKET_LAUNCHER_0001", h)
1266 self.assertIn("CUSTOMER=WILE_E_COYOTE", h)
1267 self.assertTrue(h.startswith("SHIPPING=FEDEX;"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001268
1269 def test_netscape_example_2(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001270 # Second Example transaction sequence:
1271 #
1272 # Assume all mappings from above have been cleared.
1273 #
1274 # Client receives:
1275 #
1276 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
1277 #
1278 # When client requests a URL in path "/" on this server, it sends:
1279 #
1280 # Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
1281 #
1282 # Client receives:
1283 #
1284 # Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
1285 #
1286 # When client requests a URL in path "/ammo" on this server, it sends:
1287 #
1288 # Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
1289 #
1290 # NOTE: There are two name/value pairs named "PART_NUMBER" due to
1291 # the inheritance of the "/" mapping in addition to the "/ammo" mapping.
1292
1293 c = CookieJar()
1294 headers = []
1295
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001296 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001297 headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/")
1298 res = FakeResponse(headers, "http://www.acme.com/")
1299
1300 c.extract_cookies(res, req)
1301
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001302 req = urllib.request.Request("http://www.acme.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001303 c.add_cookie_header(req)
1304
Ezio Melottib3aedd42010-11-20 19:04:17 +00001305 self.assertEqual(req.get_header("Cookie"),
1306 "PART_NUMBER=ROCKET_LAUNCHER_0001")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001307
1308 headers.append(
1309 "Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo")
1310 res = FakeResponse(headers, "http://www.acme.com/")
1311 c.extract_cookies(res, req)
1312
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001313 req = urllib.request.Request("http://www.acme.com/ammo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001314 c.add_cookie_header(req)
1315
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001316 self.assertRegex(req.get_header("Cookie"),
1317 r"PART_NUMBER=RIDING_ROCKET_0023;\s*"
1318 "PART_NUMBER=ROCKET_LAUNCHER_0001")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001319
1320 def test_ietf_example_1(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001321 #-------------------------------------------------------------------
1322 # Then we test with the examples from draft-ietf-http-state-man-mec-03.txt
1323 #
1324 # 5. EXAMPLES
1325
1326 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1327
1328 #
1329 # 5.1 Example 1
1330 #
1331 # Most detail of request and response headers has been omitted. Assume
1332 # the user agent has no stored cookies.
1333 #
1334 # 1. User Agent -> Server
1335 #
1336 # POST /acme/login HTTP/1.1
1337 # [form data]
1338 #
1339 # User identifies self via a form.
1340 #
1341 # 2. Server -> User Agent
1342 #
1343 # HTTP/1.1 200 OK
1344 # Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
1345 #
1346 # Cookie reflects user's identity.
1347
1348 cookie = interact_2965(
1349 c, 'http://www.acme.com/acme/login',
1350 'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"')
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001351 self.assertFalse(cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001352
1353 #
1354 # 3. User Agent -> Server
1355 #
1356 # POST /acme/pickitem HTTP/1.1
1357 # Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
1358 # [form data]
1359 #
1360 # User selects an item for ``shopping basket.''
1361 #
1362 # 4. Server -> User Agent
1363 #
1364 # HTTP/1.1 200 OK
1365 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
1366 # Path="/acme"
1367 #
1368 # Shopping basket contains an item.
1369
1370 cookie = interact_2965(c, 'http://www.acme.com/acme/pickitem',
1371 'Part_Number="Rocket_Launcher_0001"; '
1372 'Version="1"; Path="/acme"');
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001373 self.assertRegex(cookie,
1374 r'^\$Version="?1"?; Customer="?WILE_E_COYOTE"?; \$Path="/acme"$')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001375
1376 #
1377 # 5. User Agent -> Server
1378 #
1379 # POST /acme/shipping HTTP/1.1
1380 # Cookie: $Version="1";
1381 # Customer="WILE_E_COYOTE"; $Path="/acme";
1382 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1383 # [form data]
1384 #
1385 # User selects shipping method from form.
1386 #
1387 # 6. Server -> User Agent
1388 #
1389 # HTTP/1.1 200 OK
1390 # Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"
1391 #
1392 # New cookie reflects shipping method.
1393
1394 cookie = interact_2965(c, "http://www.acme.com/acme/shipping",
1395 'Shipping="FedEx"; Version="1"; Path="/acme"')
1396
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001397 self.assertRegex(cookie, r'^\$Version="?1"?;')
1398 self.assertRegex(cookie, r'Part_Number="?Rocket_Launcher_0001"?;'
R David Murray44b548d2016-09-08 13:59:53 -04001399 r'\s*\$Path="\/acme"')
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001400 self.assertRegex(cookie, r'Customer="?WILE_E_COYOTE"?;'
R David Murray44b548d2016-09-08 13:59:53 -04001401 r'\s*\$Path="\/acme"')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001402
1403 #
1404 # 7. User Agent -> Server
1405 #
1406 # POST /acme/process HTTP/1.1
1407 # Cookie: $Version="1";
1408 # Customer="WILE_E_COYOTE"; $Path="/acme";
1409 # Part_Number="Rocket_Launcher_0001"; $Path="/acme";
1410 # Shipping="FedEx"; $Path="/acme"
1411 # [form data]
1412 #
1413 # User chooses to process order.
1414 #
1415 # 8. Server -> User Agent
1416 #
1417 # HTTP/1.1 200 OK
1418 #
1419 # Transaction is complete.
1420
1421 cookie = interact_2965(c, "http://www.acme.com/acme/process")
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001422 self.assertRegex(cookie, r'Shipping="?FedEx"?;\s*\$Path="\/acme"')
1423 self.assertIn("WILE_E_COYOTE", cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001424
1425 #
1426 # The user agent makes a series of requests on the origin server, after
1427 # each of which it receives a new cookie. All the cookies have the same
1428 # Path attribute and (default) domain. Because the request URLs all have
1429 # /acme as a prefix, and that matches the Path attribute, each request
1430 # contains all the cookies received so far.
1431
1432 def test_ietf_example_2(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001433 # 5.2 Example 2
1434 #
1435 # This example illustrates the effect of the Path attribute. All detail
1436 # of request and response headers has been omitted. Assume the user agent
1437 # has no stored cookies.
1438
1439 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1440
1441 # Imagine the user agent has received, in response to earlier requests,
1442 # the response headers
1443 #
1444 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
1445 # Path="/acme"
1446 #
1447 # and
1448 #
1449 # Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1";
1450 # Path="/acme/ammo"
1451
1452 interact_2965(
1453 c, "http://www.acme.com/acme/ammo/specific",
1454 'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"',
1455 'Part_Number="Riding_Rocket_0023"; Version="1"; Path="/acme/ammo"')
1456
1457 # A subsequent request by the user agent to the (same) server for URLs of
1458 # the form /acme/ammo/... would include the following request header:
1459 #
1460 # Cookie: $Version="1";
1461 # Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
1462 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1463 #
1464 # Note that the NAME=VALUE pair for the cookie with the more specific Path
1465 # attribute, /acme/ammo, comes before the one with the less specific Path
1466 # attribute, /acme. Further note that the same cookie name appears more
1467 # than once.
1468
1469 cookie = interact_2965(c, "http://www.acme.com/acme/ammo/...")
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001470 self.assertRegex(cookie, r"Riding_Rocket_0023.*Rocket_Launcher_0001")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001471
1472 # A subsequent request by the user agent to the (same) server for a URL of
1473 # the form /acme/parts/ would include the following request header:
1474 #
1475 # Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"
1476 #
1477 # Here, the second cookie's Path attribute /acme/ammo is not a prefix of
1478 # the request URL, /acme/parts/, so the cookie does not get forwarded to
1479 # the server.
1480
1481 cookie = interact_2965(c, "http://www.acme.com/acme/parts/")
Ezio Melottib58e0bd2010-01-23 15:40:09 +00001482 self.assertIn("Rocket_Launcher_0001", cookie)
1483 self.assertNotIn("Riding_Rocket_0023", cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001484
1485 def test_rejection(self):
1486 # Test rejection of Set-Cookie2 responses based on domain, path, port.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001487 pol = DefaultCookiePolicy(rfc2965=True)
1488
1489 c = LWPCookieJar(policy=pol)
1490
1491 max_age = "max-age=3600"
1492
1493 # illegal domain (no embedded dots)
1494 cookie = interact_2965(c, "http://www.acme.com",
1495 'foo=bar; domain=".com"; version=1')
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001496 self.assertFalse(c)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001497
1498 # legal domain
1499 cookie = interact_2965(c, "http://www.acme.com",
1500 'ping=pong; domain="acme.com"; version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001501 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001502
1503 # illegal domain (host prefix "www.a" contains a dot)
1504 cookie = interact_2965(c, "http://www.a.acme.com",
1505 'whiz=bang; domain="acme.com"; version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001506 self.assertEqual(len(c), 1)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001507
1508 # legal domain
1509 cookie = interact_2965(c, "http://www.a.acme.com",
1510 'wow=flutter; domain=".a.acme.com"; version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001511 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001512
1513 # can't partially match an IP-address
1514 cookie = interact_2965(c, "http://125.125.125.125",
1515 'zzzz=ping; domain="125.125.125"; version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001516 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001517
1518 # illegal path (must be prefix of request path)
1519 cookie = interact_2965(c, "http://www.sol.no",
1520 'blah=rhubarb; domain=".sol.no"; path="/foo"; '
1521 'version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001522 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001523
1524 # legal path
1525 cookie = interact_2965(c, "http://www.sol.no/foo/bar",
1526 'bing=bong; domain=".sol.no"; path="/foo"; '
1527 'version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001528 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001529
1530 # illegal port (request-port not in list)
1531 cookie = interact_2965(c, "http://www.sol.no",
1532 'whiz=ffft; domain=".sol.no"; port="90,100"; '
1533 'version=1')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001534 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001535
1536 # legal port
1537 cookie = interact_2965(
1538 c, "http://www.sol.no",
1539 r'bang=wallop; version=1; domain=".sol.no"; '
1540 r'port="90,100, 80,8080"; '
1541 r'max-age=100; Comment = "Just kidding! (\"|\\\\) "')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001542 self.assertEqual(len(c), 4)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001543
1544 # port attribute without any value (current port)
1545 cookie = interact_2965(c, "http://www.sol.no",
1546 'foo9=bar; version=1; domain=".sol.no"; port; '
1547 'max-age=100;')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001548 self.assertEqual(len(c), 5)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001549
1550 # encoded path
1551 # LWP has this test, but unescaping allowed path characters seems
1552 # like a bad idea, so I think this should fail:
1553## cookie = interact_2965(c, "http://www.sol.no/foo/",
1554## r'foo8=bar; version=1; path="/%66oo"')
1555 # but this is OK, because '<' is not an allowed HTTP URL path
1556 # character:
1557 cookie = interact_2965(c, "http://www.sol.no/<oo/",
1558 r'foo8=bar; version=1; path="/%3coo"')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001559 self.assertEqual(len(c), 6)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001560
1561 # save and restore
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +00001562 filename = test.support.TESTFN
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001563
1564 try:
1565 c.save(filename, ignore_discard=True)
1566 old = repr(c)
1567
1568 c = LWPCookieJar(policy=pol)
1569 c.load(filename, ignore_discard=True)
1570 finally:
1571 try: os.unlink(filename)
1572 except OSError: pass
1573
Ezio Melottib3aedd42010-11-20 19:04:17 +00001574 self.assertEqual(old, repr(c))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001575
1576 def test_url_encoding(self):
1577 # Try some URL encodings of the PATHs.
1578 # (the behaviour here has changed from libwww-perl)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001579 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
Guido van Rossum52dbbb92008-08-18 21:44:30 +00001580 interact_2965(c, "http://www.acme.com/foo%2f%25/"
1581 "%3c%3c%0Anew%C3%A5/%C3%A5",
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001582 "foo = bar; version = 1")
1583
1584 cookie = interact_2965(
Guido van Rossumf520c052007-07-23 03:46:37 +00001585 c, "http://www.acme.com/foo%2f%25/<<%0anew\345/\346\370\345",
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001586 'bar=baz; path="/foo/"; version=1');
1587 version_re = re.compile(r'^\$version=\"?1\"?', re.I)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001588 self.assertIn("foo=bar", cookie)
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001589 self.assertRegex(cookie, version_re)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001590
1591 cookie = interact_2965(
Guido van Rossumf520c052007-07-23 03:46:37 +00001592 c, "http://www.acme.com/foo/%25/<<%0anew\345/\346\370\345")
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001593 self.assertFalse(cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001594
1595 # unicode URL doesn't raise exception
Guido van Rossumef87d6e2007-05-02 19:09:54 +00001596 cookie = interact_2965(c, "http://www.acme.com/\xfc")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001597
1598 def test_mozilla(self):
1599 # Save / load Mozilla/Netscape cookie file format.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001600 year_plus_one = time.localtime()[0] + 1
1601
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +00001602 filename = test.support.TESTFN
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001603
1604 c = MozillaCookieJar(filename,
1605 policy=DefaultCookiePolicy(rfc2965=True))
1606 interact_2965(c, "http://www.acme.com/",
1607 "foo1=bar; max-age=100; Version=1")
1608 interact_2965(c, "http://www.acme.com/",
1609 'foo2=bar; port="80"; max-age=100; Discard; Version=1')
1610 interact_2965(c, "http://www.acme.com/", "foo3=bar; secure; Version=1")
1611
1612 expires = "expires=09-Nov-%d 23:12:40 GMT" % (year_plus_one,)
1613 interact_netscape(c, "http://www.foo.com/",
1614 "fooa=bar; %s" % expires)
1615 interact_netscape(c, "http://www.foo.com/",
1616 "foob=bar; Domain=.foo.com; %s" % expires)
1617 interact_netscape(c, "http://www.foo.com/",
1618 "fooc=bar; Domain=www.foo.com; %s" % expires)
1619
1620 def save_and_restore(cj, ignore_discard):
1621 try:
1622 cj.save(ignore_discard=ignore_discard)
1623 new_c = MozillaCookieJar(filename,
1624 DefaultCookiePolicy(rfc2965=True))
1625 new_c.load(ignore_discard=ignore_discard)
1626 finally:
1627 try: os.unlink(filename)
1628 except OSError: pass
1629 return new_c
1630
1631 new_c = save_and_restore(c, True)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001632 self.assertEqual(len(new_c), 6) # none discarded
Benjamin Peterson577473f2010-01-19 00:09:57 +00001633 self.assertIn("name='foo1', value='bar'", repr(new_c))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001634
1635 new_c = save_and_restore(c, False)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001636 self.assertEqual(len(new_c), 4) # 2 of them discarded on save
Benjamin Peterson577473f2010-01-19 00:09:57 +00001637 self.assertIn("name='foo1', value='bar'", repr(new_c))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001638
1639 def test_netscape_misc(self):
1640 # Some additional Netscape cookies tests.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001641 c = CookieJar()
1642 headers = []
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001643 req = urllib.request.Request("http://foo.bar.acme.com/foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001644
1645 # Netscape allows a host part that contains dots
1646 headers.append("Set-Cookie: Customer=WILE_E_COYOTE; domain=.acme.com")
1647 res = FakeResponse(headers, "http://www.acme.com/foo")
1648 c.extract_cookies(res, req)
1649
1650 # and that the domain is the same as the host without adding a leading
1651 # dot to the domain. Should not quote even if strange chars are used
1652 # in the cookie value.
1653 headers.append("Set-Cookie: PART_NUMBER=3,4; domain=foo.bar.acme.com")
1654 res = FakeResponse(headers, "http://www.acme.com/foo")
1655 c.extract_cookies(res, req)
1656
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001657 req = urllib.request.Request("http://foo.bar.acme.com/foo")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001658 c.add_cookie_header(req)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001659 self.assertIn("PART_NUMBER=3,4", req.get_header("Cookie"))
1660 self.assertIn("Customer=WILE_E_COYOTE",req.get_header("Cookie"))
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001661
1662 def test_intranet_domains_2965(self):
1663 # Test handling of local intranet hostnames without a dot.
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001664 c = CookieJar(DefaultCookiePolicy(rfc2965=True))
1665 interact_2965(c, "http://example/",
1666 "foo1=bar; PORT; Discard; Version=1;")
1667 cookie = interact_2965(c, "http://example/",
1668 'foo2=bar; domain=".local"; Version=1')
Benjamin Peterson577473f2010-01-19 00:09:57 +00001669 self.assertIn("foo1=bar", cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001670
1671 interact_2965(c, "http://example/", 'foo3=bar; Version=1')
1672 cookie = interact_2965(c, "http://example/")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001673 self.assertIn("foo2=bar", cookie)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001674 self.assertEqual(len(c), 3)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001675
1676 def test_intranet_domains_ns(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001677 c = CookieJar(DefaultCookiePolicy(rfc2965 = False))
1678 interact_netscape(c, "http://example/", "foo1=bar")
1679 cookie = interact_netscape(c, "http://example/",
1680 'foo2=bar; domain=.local')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001681 self.assertEqual(len(c), 2)
Benjamin Peterson577473f2010-01-19 00:09:57 +00001682 self.assertIn("foo1=bar", cookie)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001683
1684 cookie = interact_netscape(c, "http://example/")
Benjamin Peterson577473f2010-01-19 00:09:57 +00001685 self.assertIn("foo2=bar", cookie)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001686 self.assertEqual(len(c), 2)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001687
1688 def test_empty_path(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001689 # Test for empty path
1690 # Broken web-server ORION/1.3.38 returns to the client response like
1691 #
1692 # Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=
1693 #
1694 # ie. with Path set to nothing.
1695 # In this case, extract_cookies() must set cookie to / (root)
1696 c = CookieJar(DefaultCookiePolicy(rfc2965 = True))
1697 headers = []
1698
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001699 req = urllib.request.Request("http://www.ants.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001700 headers.append("Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=")
1701 res = FakeResponse(headers, "http://www.ants.com/")
1702 c.extract_cookies(res, req)
1703
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001704 req = urllib.request.Request("http://www.ants.com/")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001705 c.add_cookie_header(req)
1706
Ezio Melottib3aedd42010-11-20 19:04:17 +00001707 self.assertEqual(req.get_header("Cookie"),
1708 "JSESSIONID=ABCDERANDOM123")
1709 self.assertEqual(req.get_header("Cookie2"), '$Version="1"')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001710
1711 # missing path in the request URI
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001712 req = urllib.request.Request("http://www.ants.com:8080")
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001713 c.add_cookie_header(req)
1714
Ezio Melottib3aedd42010-11-20 19:04:17 +00001715 self.assertEqual(req.get_header("Cookie"),
1716 "JSESSIONID=ABCDERANDOM123")
1717 self.assertEqual(req.get_header("Cookie2"), '$Version="1"')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001718
1719 def test_session_cookies(self):
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001720 year_plus_one = time.localtime()[0] + 1
1721
1722 # Check session cookies are deleted properly by
1723 # CookieJar.clear_session_cookies method
1724
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001725 req = urllib.request.Request('http://www.perlmeister.com/scripts')
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001726 headers = []
1727 headers.append("Set-Cookie: s1=session;Path=/scripts")
1728 headers.append("Set-Cookie: p1=perm; Domain=.perlmeister.com;"
1729 "Path=/;expires=Fri, 02-Feb-%d 23:24:20 GMT" %
1730 year_plus_one)
1731 headers.append("Set-Cookie: p2=perm;Path=/;expires=Fri, "
1732 "02-Feb-%d 23:24:20 GMT" % year_plus_one)
1733 headers.append("Set-Cookie: s2=session;Path=/scripts;"
1734 "Domain=.perlmeister.com")
1735 headers.append('Set-Cookie2: s3=session;Version=1;Discard;Path="/"')
1736 res = FakeResponse(headers, 'http://www.perlmeister.com/scripts')
1737
1738 c = CookieJar()
1739 c.extract_cookies(res, req)
1740 # How many session/permanent cookies do we have?
1741 counter = {"session_after": 0,
1742 "perm_after": 0,
1743 "session_before": 0,
1744 "perm_before": 0}
1745 for cookie in c:
1746 key = "%s_before" % cookie.value
1747 counter[key] = counter[key] + 1
1748 c.clear_session_cookies()
1749 # How many now?
1750 for cookie in c:
1751 key = "%s_after" % cookie.value
1752 counter[key] = counter[key] + 1
1753
Martin Panter46f50722016-05-26 05:35:26 +00001754 # a permanent cookie got lost accidentally
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001755 self.assertEqual(counter["perm_after"], counter["perm_before"])
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001756 # a session cookie hasn't been cleared
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001757 self.assertEqual(counter["session_after"], 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001758 # we didn't have session cookies in the first place
Serhiy Storchaka9d282f62013-11-17 13:45:02 +02001759 self.assertNotEqual(counter["session_before"], 0)
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001760
1761
1762def test_main(verbose=None):
Gregory P. Smith41e6c3d2010-07-19 23:17:22 +00001763 test.support.run_unittest(
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001764 DateTimeTests,
1765 HeaderTests,
1766 CookieTests,
Martin v. Löwisc5574e82005-03-03 10:57:37 +00001767 FileCookieJarTests,
Martin v. Löwis2a6ba902004-05-31 18:22:40 +00001768 LWPCookieTests,
1769 )
1770
1771if __name__ == "__main__":
1772 test_main(verbose=True)