1 """Mozilla / Netscape cookie loading / saving."""
5 from cookielib
import (_warn_unhandled_exception
, FileCookieJar
, LoadError
,
6 Cookie
, MISSING_FILENAME_TEXT
)
8 class MozillaCookieJar(FileCookieJar
):
11 WARNING: you may want to backup your browser's cookies file if you use
12 this class to save cookies. I *think* it works, but there have been
15 This class differs from CookieJar only in the format it uses to save and
16 load cookies to and from a file. This class uses the Mozilla/Netscape
17 `cookies.txt' format. lynx uses this file format, too.
19 Don't expect cookies saved while the browser is running to be noticed by
20 the browser (in fact, Mozilla on unix will overwrite your saved cookies if
21 you change them on disk while it's running; on Windows, you probably can't
22 save at all while the browser is running).
24 Note that the Mozilla/Netscape format will downgrade RFC2965 cookies to
25 Netscape cookies on saving.
27 In particular, the cookie version and port number information is lost,
28 together with information about whether or not Path, Port and Discard were
29 specified by the Set-Cookie2 (or Set-Cookie) header, and whether or not the
30 domain as set in the HTTP header started with a dot (yes, I'm aware some
31 domains in Netscape files start with a dot and some don't -- trust me, you
32 really don't want to know any more about this).
34 Note that though Mozilla and Netscape use the same format, they use
35 slightly different headers. The class saves cookies using the Netscape
36 header by default (Mozilla can cope with that).
39 magic_re
= "#( Netscape)? HTTP Cookie File"
41 # Netscape HTTP Cookie File
42 # http://www.netscape.com/newsref/std/cookie_spec.html
43 # This is a generated file! Do not edit.
47 def _really_load(self
, f
, filename
, ignore_discard
, ignore_expires
):
51 if not re
.search(self
.magic_re
, magic
):
54 "%r does not look like a Netscape format cookies file" %
62 # last field may be absent, so keep any trailing tab
63 if line
.endswith("\n"): line
= line
[:-1]
65 # skip comments and blank lines XXX what is $ for?
66 if (line
.strip().startswith(("#", "$")) or
70 domain
, domain_specified
, path
, secure
, expires
, name
, value
= \
72 secure
= (secure
== "TRUE")
73 domain_specified
= (domain_specified
== "TRUE")
75 # cookies.txt regards 'Set-Cookie: foo' as a cookie
76 # with no name, whereas cookielib regards it as a
77 # cookie with no value.
81 initial_dot
= domain
.startswith(".")
82 assert domain_specified
== initial_dot
89 # assume path_specified is false
90 c
= Cookie(0, name
, value
,
92 domain
, domain_specified
, initial_dot
,
100 if not ignore_discard
and c
.discard
:
102 if not ignore_expires
and c
.is_expired(now
):
109 _warn_unhandled_exception()
110 raise LoadError("invalid Netscape format cookies file %r: %r" %
113 def save(self
, filename
=None, ignore_discard
=False, ignore_expires
=False):
115 if self
.filename
is not None: filename
= self
.filename
116 else: raise ValueError(MISSING_FILENAME_TEXT
)
118 f
= open(filename
, "w")
123 if not ignore_discard
and cookie
.discard
:
125 if not ignore_expires
and cookie
.is_expired(now
):
127 if cookie
.secure
: secure
= "TRUE"
128 else: secure
= "FALSE"
129 if cookie
.domain
.startswith("."): initial_dot
= "TRUE"
130 else: initial_dot
= "FALSE"
131 if cookie
.expires
is not None:
132 expires
= str(cookie
.expires
)
135 if cookie
.value
is None:
136 # cookies.txt regards 'Set-Cookie: foo' as a cookie
137 # with no name, whereas cookielib regards it as a
138 # cookie with no value.
145 "\t".join([cookie
.domain
, initial_dot
, cookie
.path
,
146 secure
, expires
, name
, value
])+