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