1 # -*- coding: utf-8 -*-
2 """Tests for cookielib.py."""
5 from unittest
import TestCase
7 from test
import test_support
9 class DateTimeTests(TestCase
):
11 def test_time2isoz(self
):
12 from cookielib
import time2isoz
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")
22 bz
= time2isoz(500000)
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
))
27 def test_http2time(self
):
28 from cookielib
import http2time
31 return time
.gmtime(http2time(text
))[:6]
33 self
.assertEquals(parse_date("01 Jan 2001"), (2001, 1, 1, 0, 0, 0.0))
35 # this test will break around year 2070
36 self
.assertEquals(parse_date("03-Feb-20"), (2020, 2, 3, 0, 0, 0.0))
38 # this test will break around year 2048
39 self
.assertEquals(parse_date("03-Feb-98"), (1998, 2, 3, 0, 0, 0.0))
41 def test_http2time_formats(self
):
42 from cookielib
import http2time
, time2isoz
44 # test http2time for supported dates. Test cases with 2 digit year
45 # will probably break in year 2044.
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
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)
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)
61 # A few tests with extra space at various places
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
))
74 t2
= http2time(s
.lower())
75 t3
= http2time(s
.upper())
77 self
.assert_(t
== t2
== t3
== test_t
,
78 "'%s' => %s, %s, %s (%s)" % (s
, t
, t2
, t3
, test_t
))
80 def test_http2time_garbage(self
):
81 from cookielib
import http2time
86 'Mandag 16. September 1996',
91 '01-01-1980 25:00:00',
92 '01-01-1980 00:61:00',
93 '01-01-1980 00:00:62',
95 self
.assert_(http2time(test
) is None,
96 "http2time(%s) is not None\n"
97 "http2time(test) %s" % (test
, http2time(test
))
101 class HeaderTests(TestCase
):
102 def test_parse_ns_headers(self
):
103 from cookielib
import parse_ns_headers
105 # quotes should be stripped
106 expected
= [[('foo', 'bar'), ('expires', 2209069412L), ('version', '0')]]
108 'foo=bar; expires=01 Jan 2040 22:23:32 GMT',
109 'foo=bar; expires="01 Jan 2040 22:23:32 GMT"',
111 self
.assertEquals(parse_ns_headers([hdr
]), expected
)
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
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
)
123 def test_join_header_words(self
):
124 from cookielib
import join_header_words
126 joined
= join_header_words([[("foo", None), ("bar", "baz")]])
127 self
.assertEquals(joined
, "foo; bar=baz")
129 self
.assertEquals(join_header_words([[]]), "")
131 def test_split_header_words(self
):
132 from cookielib
import split_header_words
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", "")]]),
153 for arg
, expect
in tests
:
155 result
= split_header_words([arg
])
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
, """
165 """ % (arg
, expect
, result
))
167 def test_roundtrip(self
):
168 from cookielib
import split_header_words
, join_header_words
172 ("foo=bar", "foo=bar"),
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'),
182 ('text/html; charset=iso-8859-1',
183 'text/html; charset="iso-8859-1"'),
185 ('foo="bar"; port="80,81"; discard, bar=baz',
186 'foo=bar; port="80,81"; discard, bar=baz'),
188 (r
'Basic realm="\"foo\\\\bar\""',
189 r
'Basic; realm="\"foo\\\\bar\""')
192 for arg
, expect
in tests
:
193 input = split_header_words([arg
])
194 res
= join_header_words(input)
195 self
.assertEquals(res
, expect
, """
200 """ % (arg
, expect
, res
, input))
204 def __init__(self
, headers
=[], url
=None):
206 headers: list of RFC822-style 'Key: value' strings
208 import mimetools
, StringIO
209 f
= StringIO
.StringIO("\n".join(headers
))
210 self
._headers
= mimetools
.Message(f
)
212 def info(self
): return self
._headers
214 def interact_2965(cookiejar
, url
, *set_cookie_hdrs
):
215 return _interact(cookiejar
, url
, set_cookie_hdrs
, "Set-Cookie2")
217 def interact_netscape(cookiejar
, url
, *set_cookie_hdrs
):
218 return _interact(cookiejar
, url
, set_cookie_hdrs
, "Set-Cookie")
220 def _interact(cookiejar
, url
, set_cookie_hdrs
, hdr_name
):
221 """Perform a single request / response cycle, returning Cookie: header."""
222 from urllib2
import Request
224 cookiejar
.add_cookie_header(req
)
225 cookie_hdr
= req
.get_header("Cookie", "")
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
)
234 class 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
240 interact_netscape(c
, "http://www.acme.com/", 'boo')
241 self
.assertEqual(c
._cookies
["www.acme.com"]["/"]["boo"].value
, None)
243 c
.save(filename
, ignore_discard
=True)
245 c
.load(filename
, ignore_discard
=True)
247 try: os
.unlink(filename
)
249 self
.assertEqual(c
._cookies
["www.acme.com"]["/"]["boo"].value
, None)
252 class CookieTests(TestCase
):
254 # Get rid of string comparisons where not actually testing str / repr.
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
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.
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.
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
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),
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
)
330 def test_missing_value(self
):
331 from cookielib
import MozillaCookieJar
, lwp_cookie_str
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'))
349 c
.save(ignore_expires
=True, ignore_discard
=True)
351 c
= MozillaCookieJar(filename
)
352 c
.revert(ignore_expires
=True, ignore_discard
=True)
354 os
.unlink(c
.filename
)
355 # cookies unchanged apart from lost info re. whether path was specified
358 re
.sub("path_specified=%s" % True, "path_specified=%s" % False,
361 self
.assertEquals(interact_netscape(c
, "http://www.acme.com/foo/"),
364 def test_ns_parser(self
):
365 from cookielib
import CookieJar
, DEFAULT_HTTP_PORT
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"')
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
)
382 self
.assert_(cookie
.has_nonstandard_attr("blArgh") and
383 not cookie
.has_nonstandard_attr("blargh"))
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
)
391 cookie
= c
._cookies
["www.acme.com"]["/"]["nini"]
392 self
.assert_(cookie
.port
is None)
393 self
.assert_(not cookie
.port_specified
)
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)
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
407 interact_netscape(c
, "http://www.acme.com/", 'expires=eggs')
408 interact_netscape(c
, "http://www.acme.com/", 'version=eggs; spam=eggs')
410 cookies
= c
._cookies
["www.acme.com"]["/"]
411 self
.assert_('expires' in cookies
)
412 self
.assert_('version' in cookies
)
414 def test_expires(self
):
415 from cookielib
import time2netscape
, CookieJar
417 # if expires is in future, keep cookie...
419 future
= time2netscape(time
.time()+3600)
420 interact_netscape(c
, "http://www.acme.com/", 'spam="bar"; expires=%s' %
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' %
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
)
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' %
435 interact_netscape(c
, "http://www.acme.com/", 'bar="bar"; expires=%s' %
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)
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
)
452 # XXX RFC 2965 expiry rules (some apply to V0 too)
454 def test_default_path(self
):
455 from cookielib
import CookieJar
, DefaultCookiePolicy
458 pol
= DefaultCookiePolicy(rfc2965
=True)
461 interact_2965(c
, "http://www.acme.com/", 'spam="bar"; Version="1"')
462 self
.assert_("/" in c
._cookies
["www.acme.com"])
465 interact_2965(c
, "http://www.acme.com/blah", 'eggs="bar"; Version="1"')
466 self
.assert_("/" in c
._cookies
["www.acme.com"])
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"])
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"])
481 interact_netscape(c
, "http://www.acme.com/", 'spam="bar"')
482 self
.assert_("/" in c
._cookies
["www.acme.com"])
485 interact_netscape(c
, "http://www.acme.com/blah", 'eggs="bar"')
486 self
.assert_("/" in c
._cookies
["www.acme.com"])
489 interact_netscape(c
, "http://www.acme.com/blah/rhubarb", 'eggs="bar"')
490 self
.assert_("/blah" in c
._cookies
["www.acme.com"])
493 interact_netscape(c
, "http://www.acme.com/blah/rhubarb/", 'eggs="bar"')
494 self
.assert_("/blah/rhubarb" in c
._cookies
["www.acme.com"])
496 def test_escape_path(self
):
497 from cookielib
import escape_path
500 ("/foo%2f/bar", "/foo%2F/bar"),
501 ("/foo%2F/bar", "/foo%2F/bar"),
503 ("/foo%%/bar", "/foo%%/bar"),
505 ("/fo%19o/bar", "/fo%19o/bar"),
506 ("/fo%7do/bar", "/fo%7Do/bar"),
508 ("/foo/bar&", "/foo/bar&"),
509 ("/foo//bar", "/foo//bar"),
510 ("\176/foo/bar", "\176/foo/bar"),
512 ("/foo\031/bar", "/foo%19/bar"),
513 ("/\175foo/bar", "/%7Dfoo/bar"),
515 (u
"/foo/bar\uabcd", "/foo/bar%EA%AF%8D"), # UTF-8 encoded
517 for arg
, result
in cases
:
518 self
.assertEquals(escape_path(arg
), result
)
520 def test_request_path(self
):
521 from urllib2
import Request
522 from cookielib
import request_path
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")
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
), "/")
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
)
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")
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."))
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")
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("", ""))
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", ""))
629 def test_wrong_domain(self
):
630 # Cookies whose effective request-host name does not domain-match the
631 # domain are rejected.
633 # XXX far from complete
634 from cookielib
import CookieJar
636 interact_2965(c
, "http://www.nasty.com/",
637 'foo=bar; domain=friendly.org; Version="1"')
638 self
.assertEquals(len(c
), 0)
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
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/"),
656 # ...unless requested otherwise
657 pol
= DefaultCookiePolicy(
658 strict_ns_domain
=DefaultCookiePolicy
.DomainStrictNonDomain
)
660 self
.assertEquals(interact_netscape(c
, "http://www.foo.net/"), "")
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
,
672 self
.assertEquals(c
._cookies
[".foo.net"]["/foo/bar"]["spam2"].value
,
674 self
.assertEquals(interact_netscape(c
, "http://foo.net/foo/bar/"),
675 "spam2=eggs; spam1=eggs; ns=bar")
677 # top-level domain is too general
678 interact_netscape(c
, "http://foo.net/", 'nini="ni"; domain=.net')
679 self
.assertEquals(len(c
), 3)
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
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)
690 def test_two_component_domain_rfc2965(self
):
691 from cookielib
import CookieJar
, DefaultCookiePolicy
693 pol
= DefaultCookiePolicy(rfc2965
=True)
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/"), "")
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")
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
,
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"')
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)
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)
736 def test_domain_allow(self
):
737 from cookielib
import CookieJar
, DefaultCookiePolicy
738 from urllib2
import Request
740 c
= CookieJar(policy
=DefaultCookiePolicy(
741 blocked_domains
=["acme.com"],
742 allowed_domains
=["www.acme.com"]))
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)
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)
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)
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"))
770 def test_domain_block(self
):
771 from cookielib
import CookieJar
, DefaultCookiePolicy
772 from urllib2
import Request
774 pol
= DefaultCookiePolicy(
775 rfc2965
=True, blocked_domains
=[".acme.com"])
776 c
= CookieJar(policy
=pol
)
777 headers
= ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
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)
784 p
= pol
.set_blocked_domains(["acme.com"])
785 c
.extract_cookies(res
, req
)
786 self
.assertEquals(len(c
), 1)
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")))
799 pol
.set_blocked_domains([".acme.com"])
800 c
.extract_cookies(res
, req
)
801 self
.assertEquals(len(c
), 1)
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"))
813 def test_secure(self
):
814 from cookielib
import CookieJar
, DefaultCookiePolicy
816 for ns
in True, False:
817 for whitespace
in " ", "":
820 pol
= DefaultCookiePolicy(rfc2965
=False)
821 int = interact_netscape
824 pol
= DefaultCookiePolicy(rfc2965
=True)
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
))
832 not c
._cookies
["www.acme.com"]["/"]["foo1"].secure
,
833 "non-secure cookie registered secure")
835 c
._cookies
["www.acme.com"]["/"]["foo2"].secure
,
836 "secure cookie registered non-secure")
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')
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")
853 self
.assertEquals(len(c
), 1)
854 c
.add_cookie_header(req
)
855 self
.assert_(req
.has_header("Cookie"))
857 def test_domain_mirror(self
):
858 from cookielib
import CookieJar
, DefaultCookiePolicy
860 pol
= DefaultCookiePolicy(rfc2965
=True)
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")
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")
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")
882 def test_path_mirror(self
):
883 from cookielib
import CookieJar
, DefaultCookiePolicy
885 pol
= DefaultCookiePolicy(rfc2965
=True)
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")
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")
900 def test_port_mirror(self
):
901 from cookielib
import CookieJar
, DefaultCookiePolicy
903 pol
= DefaultCookiePolicy(rfc2965
=True)
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")
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")
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")
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 "
934 def test_no_return_comment(self
):
935 from cookielib
import CookieJar
, DefaultCookiePolicy
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
)
945 "Comment or CommentURL cookie-attributes returned to server")
947 def test_Cookie_iterator(self
):
948 from cookielib
import CookieJar
, Cookie
, DefaultCookiePolicy
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! (\"|\\\\) "')
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/"]
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
])
981 def test_parse_ns_headers(self
):
982 from cookielib
import parse_ns_headers
984 # missing domain value (invalid cookie)
986 parse_ns_headers(["foo=bar; path=/; domain"]),
988 ("path", "/"), ("domain", None), ("version", "0")]]
990 # invalid expires value
992 parse_ns_headers(["foo=bar; expires=Foo Bar 12 33:22:11 2000"]),
993 [[("foo", "bar"), ("expires", None), ("version", "0")]]
995 # missing cookie value (valid cookie)
997 parse_ns_headers(["foo"]),
998 [[("foo", None), ("version", "0")]]
1000 # shouldn't add version if header is empty
1001 self
.assertEquals(parse_ns_headers([""]), [])
1003 def test_bad_cookie_header(self
):
1005 def cookiejar_from_cookie_headers(headers
):
1006 from cookielib
import CookieJar
1007 from urllib2
import Request
1009 req
= Request("http://www.example.com/")
1010 r
= FakeResponse(headers
, "http://www.example.com/")
1011 c
.extract_cookies(r
, req
)
1014 # none of these bad headers should cause an exception to be raised
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"],
1021 ["Set-Cookie: b=foo; max-age=oops"],
1023 c
= cookiejar_from_cookie_headers(headers
)
1024 # these bad cookies shouldn't be set
1025 self
.assertEquals(len(c
), 0)
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)
1034 class LWPCookieTests(TestCase
):
1035 # Tests taken from libwww-perl, with a few modifications and additions.
1037 def test_netscape_example_1(self
):
1038 from cookielib
import CookieJar
, DefaultCookiePolicy
1039 from urllib2
import Request
1041 #-------------------------------------------------------------------
1042 # First we check that it works for the original example at
1043 # http://www.netscape.com/newsref/std/cookie_spec.html
1045 # Client requests a document, and receives in the response:
1047 # Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
1049 # When client requests a URL in path "/" on this server, it sends:
1051 # Cookie: CUSTOMER=WILE_E_COYOTE
1053 # Client requests a document, and receives in the response:
1055 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
1057 # When client requests a URL in path "/" on this server, it sends:
1059 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
1063 # Set-Cookie: SHIPPING=FEDEX; path=/fo
1065 # When client requests a URL in path "/" on this server, it sends:
1067 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
1069 # When client requests a URL in path "/foo" on this server, it sends:
1071 # Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX
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.
1077 year_plus_one
= time
.localtime()[0] + 1
1081 c
= CookieJar(DefaultCookiePolicy(rfc2965
= True))
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"})
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
)
1094 req
= Request("http://www.acme.com/")
1095 c
.add_cookie_header(req
)
1097 self
.assertEqual(req
.get_header("Cookie"), "CUSTOMER=WILE_E_COYOTE")
1098 self
.assertEqual(req
.get_header("Cookie2"), '$Version="1"')
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
)
1104 req
= Request("http://www.acme.com/foo/bar")
1105 c
.add_cookie_header(req
)
1107 h
= req
.get_header("Cookie")
1108 self
.assert_("PART_NUMBER=ROCKET_LAUNCHER_0001" in h
and
1109 "CUSTOMER=WILE_E_COYOTE" in h
)
1111 headers
.append('Set-Cookie: SHIPPING=FEDEX; path=/foo')
1112 res
= FakeResponse(headers
, "http://www.acme.com")
1113 c
.extract_cookies(res
, req
)
1115 req
= Request("http://www.acme.com/")
1116 c
.add_cookie_header(req
)
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
)
1123 req
= Request("http://www.acme.com/foo/")
1124 c
.add_cookie_header(req
)
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;")))
1131 def test_netscape_example_2(self
):
1132 from cookielib
import CookieJar
1133 from urllib2
import Request
1135 # Second Example transaction sequence:
1137 # Assume all mappings from above have been cleared.
1141 # Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
1143 # When client requests a URL in path "/" on this server, it sends:
1145 # Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
1149 # Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
1151 # When client requests a URL in path "/ammo" on this server, it sends:
1153 # Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
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.
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/")
1165 c
.extract_cookies(res
, req
)
1167 req
= Request("http://www.acme.com/")
1168 c
.add_cookie_header(req
)
1170 self
.assertEquals(req
.get_header("Cookie"),
1171 "PART_NUMBER=ROCKET_LAUNCHER_0001")
1174 "Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo")
1175 res
= FakeResponse(headers
, "http://www.acme.com/")
1176 c
.extract_cookies(res
, req
)
1178 req
= Request("http://www.acme.com/ammo")
1179 c
.add_cookie_header(req
)
1181 self
.assert_(re
.search(r
"PART_NUMBER=RIDING_ROCKET_0023;\s*"
1182 "PART_NUMBER=ROCKET_LAUNCHER_0001",
1183 req
.get_header("Cookie")))
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
1192 c
= CookieJar(DefaultCookiePolicy(rfc2965
=True))
1197 # Most detail of request and response headers has been omitted. Assume
1198 # the user agent has no stored cookies.
1200 # 1. User Agent -> Server
1202 # POST /acme/login HTTP/1.1
1205 # User identifies self via a form.
1207 # 2. Server -> User Agent
1210 # Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
1212 # Cookie reflects user's identity.
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
)
1220 # 3. User Agent -> Server
1222 # POST /acme/pickitem HTTP/1.1
1223 # Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
1226 # User selects an item for ``shopping basket.''
1228 # 4. Server -> User Agent
1231 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
1234 # Shopping basket contains an item.
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"$',
1244 # 5. User Agent -> Server
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"
1252 # User selects shipping method from form.
1254 # 6. Server -> User Agent
1257 # Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"
1259 # New cookie reflects shipping method.
1261 cookie
= interact_2965(c
, "http://www.acme.com/acme/shipping",
1262 'Shipping="FedEx"; Version="1"; Path="/acme"')
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"',
1271 # 7. User Agent -> Server
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"
1280 # User chooses to process order.
1282 # 8. Server -> User Agent
1286 # Transaction is complete.
1288 cookie
= interact_2965(c
, "http://www.acme.com/acme/process")
1290 re
.search(r
'Shipping="?FedEx"?;\s*\$Path="\/acme"', cookie
) and
1291 "WILE_E_COYOTE" in cookie
)
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.
1300 def test_ietf_example_2(self
):
1301 from cookielib
import CookieJar
, DefaultCookiePolicy
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.
1309 c
= CookieJar(DefaultCookiePolicy(rfc2965
=True))
1311 # Imagine the user agent has received, in response to earlier requests,
1312 # the response headers
1314 # Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
1319 # Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1";
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"')
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:
1330 # Cookie: $Version="1";
1331 # Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
1332 # Part_Number="Rocket_Launcher_0001"; $Path="/acme"
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
1339 cookie
= interact_2965(c
, "http://www.acme.com/acme/ammo/...")
1341 re
.search(r
"Riding_Rocket_0023.*Rocket_Launcher_0001", cookie
))
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:
1346 # Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"
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
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
)
1356 def test_rejection(self
):
1357 # Test rejection of Set-Cookie2 responses based on domain, path, port.
1358 from cookielib
import DefaultCookiePolicy
, LWPCookieJar
1360 pol
= DefaultCookiePolicy(rfc2965
=True)
1362 c
= LWPCookieJar(policy
=pol
)
1364 max_age
= "max-age=3600"
1366 # illegal domain (no embedded dots)
1367 cookie
= interact_2965(c
, "http://www.acme.com",
1368 'foo=bar; domain=".com"; version=1')
1372 cookie
= interact_2965(c
, "http://www.acme.com",
1373 'ping=pong; domain="acme.com"; version=1')
1374 self
.assertEquals(len(c
), 1)
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)
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)
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)
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"; '
1395 self
.assertEquals(len(c
), 2)
1398 cookie
= interact_2965(c
, "http://www.sol.no/foo/bar",
1399 'bing=bong; domain=".sol.no"; path="/foo"; '
1401 self
.assertEquals(len(c
), 3)
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"; '
1407 self
.assertEquals(len(c
), 3)
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)
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; '
1421 self
.assertEquals(len(c
), 5)
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
1430 cookie
= interact_2965(c
, "http://www.sol.no/<oo/",
1431 r
'foo8=bar; version=1; path="/%3coo"')
1432 self
.assertEquals(len(c
), 6)
1435 filename
= test_support
.TESTFN
1438 c
.save(filename
, ignore_discard
=True)
1441 c
= LWPCookieJar(policy
=pol
)
1442 c
.load(filename
, ignore_discard
=True)
1444 try: os
.unlink(filename
)
1445 except OSError: pass
1447 self
.assertEquals(old
, repr(c
))
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
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")
1458 cookie
= interact_2965(
1459 c
, "http://www.acme.com/foo%2f%25/<<%0anewå/æøå",
1460 'bar=baz; path="/foo/"; version=1');
1461 version_re
= re
.compile(r
'^\$version=\"?1\"?', re
.I
)
1462 self
.assert_("foo=bar" in cookie
and version_re
.search(cookie
))
1464 cookie
= interact_2965(
1465 c
, "http://www.acme.com/foo/%25/<<%0anewå/æøå")
1466 self
.assert_(not cookie
)
1468 # unicode URL doesn't raise exception
1469 cookie
= interact_2965(c
, u
"http://www.acme.com/\xfc")
1471 def test_mozilla(self
):
1472 # Save / load Mozilla/Netscape cookie file format.
1473 from cookielib
import MozillaCookieJar
, DefaultCookiePolicy
1475 year_plus_one
= time
.localtime()[0] + 1
1477 filename
= test_support
.TESTFN
1479 c
= MozillaCookieJar(filename
,
1480 policy
=DefaultCookiePolicy(rfc2965
=True))
1481 interact_2965(c
, "http://www.acme.com/",
1482 "foo1=bar; max-age=100; Version=1")
1483 interact_2965(c
, "http://www.acme.com/",
1484 'foo2=bar; port="80"; max-age=100; Discard; Version=1')
1485 interact_2965(c
, "http://www.acme.com/", "foo3=bar; secure; Version=1")
1487 expires
= "expires=09-Nov-%d 23:12:40 GMT" % (year_plus_one
,)
1488 interact_netscape(c
, "http://www.foo.com/",
1489 "fooa=bar; %s" % expires
)
1490 interact_netscape(c
, "http://www.foo.com/",
1491 "foob=bar; Domain=.foo.com; %s" % expires
)
1492 interact_netscape(c
, "http://www.foo.com/",
1493 "fooc=bar; Domain=www.foo.com; %s" % expires
)
1495 def save_and_restore(cj
, ignore_discard
):
1497 cj
.save(ignore_discard
=ignore_discard
)
1498 new_c
= MozillaCookieJar(filename
,
1499 DefaultCookiePolicy(rfc2965
=True))
1500 new_c
.load(ignore_discard
=ignore_discard
)
1502 try: os
.unlink(filename
)
1503 except OSError: pass
1506 new_c
= save_and_restore(c
, True)
1507 self
.assertEquals(len(new_c
), 6) # none discarded
1508 self
.assert_("name='foo1', value='bar'" in repr(new_c
))
1510 new_c
= save_and_restore(c
, False)
1511 self
.assertEquals(len(new_c
), 4) # 2 of them discarded on save
1512 self
.assert_("name='foo1', value='bar'" in repr(new_c
))
1514 def test_netscape_misc(self
):
1515 # Some additional Netscape cookies tests.
1516 from cookielib
import CookieJar
1517 from urllib2
import Request
1521 req
= Request("http://foo.bar.acme.com/foo")
1523 # Netscape allows a host part that contains dots
1524 headers
.append("Set-Cookie: Customer=WILE_E_COYOTE; domain=.acme.com")
1525 res
= FakeResponse(headers
, "http://www.acme.com/foo")
1526 c
.extract_cookies(res
, req
)
1528 # and that the domain is the same as the host without adding a leading
1529 # dot to the domain. Should not quote even if strange chars are used
1530 # in the cookie value.
1531 headers
.append("Set-Cookie: PART_NUMBER=3,4; domain=foo.bar.acme.com")
1532 res
= FakeResponse(headers
, "http://www.acme.com/foo")
1533 c
.extract_cookies(res
, req
)
1535 req
= Request("http://foo.bar.acme.com/foo")
1536 c
.add_cookie_header(req
)
1538 "PART_NUMBER=3,4" in req
.get_header("Cookie") and
1539 "Customer=WILE_E_COYOTE" in req
.get_header("Cookie"))
1541 def test_intranet_domains_2965(self
):
1542 # Test handling of local intranet hostnames without a dot.
1543 from cookielib
import CookieJar
, DefaultCookiePolicy
1545 c
= CookieJar(DefaultCookiePolicy(rfc2965
=True))
1546 interact_2965(c
, "http://example/",
1547 "foo1=bar; PORT; Discard; Version=1;")
1548 cookie
= interact_2965(c
, "http://example/",
1549 'foo2=bar; domain=".local"; Version=1')
1550 self
.assert_("foo1=bar" in cookie
)
1552 interact_2965(c
, "http://example/", 'foo3=bar; Version=1')
1553 cookie
= interact_2965(c
, "http://example/")
1554 self
.assert_("foo2=bar" in cookie
and len(c
) == 3)
1556 def test_intranet_domains_ns(self
):
1557 from cookielib
import CookieJar
, DefaultCookiePolicy
1559 c
= CookieJar(DefaultCookiePolicy(rfc2965
= False))
1560 interact_netscape(c
, "http://example/", "foo1=bar")
1561 cookie
= interact_netscape(c
, "http://example/",
1562 'foo2=bar; domain=.local')
1563 self
.assertEquals(len(c
), 2)
1564 self
.assert_("foo1=bar" in cookie
)
1566 cookie
= interact_netscape(c
, "http://example/")
1567 self
.assert_("foo2=bar" in cookie
)
1568 self
.assertEquals(len(c
), 2)
1570 def test_empty_path(self
):
1571 from cookielib
import CookieJar
, DefaultCookiePolicy
1572 from urllib2
import Request
1574 # Test for empty path
1575 # Broken web-server ORION/1.3.38 returns to the client response like
1577 # Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=
1579 # ie. with Path set to nothing.
1580 # In this case, extract_cookies() must set cookie to / (root)
1581 c
= CookieJar(DefaultCookiePolicy(rfc2965
= True))
1584 req
= Request("http://www.ants.com/")
1585 headers
.append("Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=")
1586 res
= FakeResponse(headers
, "http://www.ants.com/")
1587 c
.extract_cookies(res
, req
)
1589 req
= Request("http://www.ants.com/")
1590 c
.add_cookie_header(req
)
1592 self
.assertEquals(req
.get_header("Cookie"),
1593 "JSESSIONID=ABCDERANDOM123")
1594 self
.assertEquals(req
.get_header("Cookie2"), '$Version="1"')
1596 # missing path in the request URI
1597 req
= Request("http://www.ants.com:8080")
1598 c
.add_cookie_header(req
)
1600 self
.assertEquals(req
.get_header("Cookie"),
1601 "JSESSIONID=ABCDERANDOM123")
1602 self
.assertEquals(req
.get_header("Cookie2"), '$Version="1"')
1604 def test_session_cookies(self
):
1605 from cookielib
import CookieJar
1606 from urllib2
import Request
1608 year_plus_one
= time
.localtime()[0] + 1
1610 # Check session cookies are deleted properly by
1611 # CookieJar.clear_session_cookies method
1613 req
= Request('http://www.perlmeister.com/scripts')
1615 headers
.append("Set-Cookie: s1=session;Path=/scripts")
1616 headers
.append("Set-Cookie: p1=perm; Domain=.perlmeister.com;"
1617 "Path=/;expires=Fri, 02-Feb-%d 23:24:20 GMT" %
1619 headers
.append("Set-Cookie: p2=perm;Path=/;expires=Fri, "
1620 "02-Feb-%d 23:24:20 GMT" % year_plus_one
)
1621 headers
.append("Set-Cookie: s2=session;Path=/scripts;"
1622 "Domain=.perlmeister.com")
1623 headers
.append('Set-Cookie2: s3=session;Version=1;Discard;Path="/"')
1624 res
= FakeResponse(headers
, 'http://www.perlmeister.com/scripts')
1627 c
.extract_cookies(res
, req
)
1628 # How many session/permanent cookies do we have?
1629 counter
= {"session_after": 0,
1631 "session_before": 0,
1634 key
= "%s_before" % cookie
.value
1635 counter
[key
] = counter
[key
] + 1
1636 c
.clear_session_cookies()
1639 key
= "%s_after" % cookie
.value
1640 counter
[key
] = counter
[key
] + 1
1643 # a permanent cookie got lost accidently
1644 counter
["perm_after"] != counter
["perm_before"] or
1645 # a session cookie hasn't been cleared
1646 counter
["session_after"] != 0 or
1647 # we didn't have session cookies in the first place
1648 counter
["session_before"] == 0))
1651 def test_main(verbose
=None):
1652 from test
import test_sets
1653 test_support
.run_unittest(
1661 if __name__
== "__main__":
1662 test_main(verbose
=True)