2004-05-31 15:22:40 -03:00
|
|
|
"""Mozilla / Netscape cookie loading / saving."""
|
|
|
|
|
2006-05-18 03:18:06 -03:00
|
|
|
import re, time
|
2004-05-31 15:22:40 -03:00
|
|
|
|
2006-05-08 14:48:01 -03:00
|
|
|
from cookielib import (_warn_unhandled_exception, FileCookieJar, LoadError,
|
|
|
|
Cookie, MISSING_FILENAME_TEXT)
|
2004-05-31 15:22:40 -03:00
|
|
|
|
|
|
|
class MozillaCookieJar(FileCookieJar):
|
|
|
|
"""
|
|
|
|
|
|
|
|
WARNING: you may want to backup your browser's cookies file if you use
|
|
|
|
this class to save cookies. I *think* it works, but there have been
|
|
|
|
bugs in the past!
|
|
|
|
|
|
|
|
This class differs from CookieJar only in the format it uses to save and
|
|
|
|
load cookies to and from a file. This class uses the Mozilla/Netscape
|
|
|
|
`cookies.txt' format. lynx uses this file format, too.
|
|
|
|
|
|
|
|
Don't expect cookies saved while the browser is running to be noticed by
|
|
|
|
the browser (in fact, Mozilla on unix will overwrite your saved cookies if
|
|
|
|
you change them on disk while it's running; on Windows, you probably can't
|
|
|
|
save at all while the browser is running).
|
|
|
|
|
|
|
|
Note that the Mozilla/Netscape format will downgrade RFC2965 cookies to
|
|
|
|
Netscape cookies on saving.
|
|
|
|
|
|
|
|
In particular, the cookie version and port number information is lost,
|
|
|
|
together with information about whether or not Path, Port and Discard were
|
|
|
|
specified by the Set-Cookie2 (or Set-Cookie) header, and whether or not the
|
|
|
|
domain as set in the HTTP header started with a dot (yes, I'm aware some
|
|
|
|
domains in Netscape files start with a dot and some don't -- trust me, you
|
|
|
|
really don't want to know any more about this).
|
|
|
|
|
|
|
|
Note that though Mozilla and Netscape use the same format, they use
|
|
|
|
slightly different headers. The class saves cookies using the Netscape
|
|
|
|
header by default (Mozilla can cope with that).
|
|
|
|
|
|
|
|
"""
|
|
|
|
magic_re = "#( Netscape)? HTTP Cookie File"
|
|
|
|
header = """\
|
Merged revisions 83392,83426 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/release27-maint
................
r83392 | georg.brandl | 2010-08-01 10:22:05 +0200 (So, 01 Aug 2010) | 1 line
#8471: reset _SpoofOut.buf to an empty string when truncating; if Unicode had been output previously, it had been coerced to a Unicode string, potentially making subsequent prints behave differently or raise UnicodeErrors.
................
r83426 | georg.brandl | 2010-08-01 21:06:51 +0200 (So, 01 Aug 2010) | 27 lines
Merged revisions 83370,83372-83374,83384 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/py3k
........
r83370 | georg.brandl | 2010-07-31 23:51:48 +0200 (Sa, 31 Jul 2010) | 5 lines
#8198: the Helper class should not save the stdin and stdout objects
at import time, rather by default use the current streams like the
other APIs that output help.
........
r83372 | georg.brandl | 2010-08-01 00:05:54 +0200 (So, 01 Aug 2010) | 1 line
#4007: remove *.a and *.so.X.Y files in "make clean".
........
r83373 | georg.brandl | 2010-08-01 00:11:11 +0200 (So, 01 Aug 2010) | 1 line
#5147: revert accidental indentation of header constant for MozillaCookieJar.
........
r83374 | georg.brandl | 2010-08-01 00:32:52 +0200 (So, 01 Aug 2010) | 1 line
#5146: handle UID THREAD command correctly.
........
r83384 | georg.brandl | 2010-08-01 08:32:55 +0200 (So, 01 Aug 2010) | 1 line
Build properties using lambdas. This makes test_pyclbr pass again, because it does not think that input and output are methods anymore.
........
................
2010-08-01 19:05:31 -03:00
|
|
|
# Netscape HTTP Cookie File
|
|
|
|
# http://www.netscape.com/newsref/std/cookie_spec.html
|
|
|
|
# This is a generated file! Do not edit.
|
2004-05-31 15:22:40 -03:00
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
def _really_load(self, f, filename, ignore_discard, ignore_expires):
|
|
|
|
now = time.time()
|
|
|
|
|
|
|
|
magic = f.readline()
|
|
|
|
if not re.search(self.magic_re, magic):
|
|
|
|
f.close()
|
2005-12-23 17:24:35 -04:00
|
|
|
raise LoadError(
|
2006-05-08 14:48:01 -03:00
|
|
|
"%r does not look like a Netscape format cookies file" %
|
2004-05-31 15:22:40 -03:00
|
|
|
filename)
|
|
|
|
|
|
|
|
try:
|
|
|
|
while 1:
|
|
|
|
line = f.readline()
|
|
|
|
if line == "": break
|
|
|
|
|
|
|
|
# last field may be absent, so keep any trailing tab
|
|
|
|
if line.endswith("\n"): line = line[:-1]
|
|
|
|
|
|
|
|
# skip comments and blank lines XXX what is $ for?
|
2006-06-09 17:43:48 -03:00
|
|
|
if (line.strip().startswith(("#", "$")) or
|
2004-05-31 15:22:40 -03:00
|
|
|
line.strip() == ""):
|
|
|
|
continue
|
|
|
|
|
|
|
|
domain, domain_specified, path, secure, expires, name, value = \
|
|
|
|
line.split("\t")
|
|
|
|
secure = (secure == "TRUE")
|
|
|
|
domain_specified = (domain_specified == "TRUE")
|
|
|
|
if name == "":
|
2005-03-03 06:57:37 -04:00
|
|
|
# cookies.txt regards 'Set-Cookie: foo' as a cookie
|
|
|
|
# with no name, whereas cookielib regards it as a
|
|
|
|
# cookie with no value.
|
2004-05-31 15:22:40 -03:00
|
|
|
name = value
|
|
|
|
value = None
|
|
|
|
|
|
|
|
initial_dot = domain.startswith(".")
|
|
|
|
assert domain_specified == initial_dot
|
|
|
|
|
|
|
|
discard = False
|
|
|
|
if expires == "":
|
|
|
|
expires = None
|
|
|
|
discard = True
|
|
|
|
|
|
|
|
# assume path_specified is false
|
|
|
|
c = Cookie(0, name, value,
|
|
|
|
None, False,
|
|
|
|
domain, domain_specified, initial_dot,
|
|
|
|
path, False,
|
|
|
|
secure,
|
|
|
|
expires,
|
|
|
|
discard,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
{})
|
|
|
|
if not ignore_discard and c.discard:
|
|
|
|
continue
|
|
|
|
if not ignore_expires and c.is_expired(now):
|
|
|
|
continue
|
|
|
|
self.set_cookie(c)
|
|
|
|
|
2006-05-08 14:48:01 -03:00
|
|
|
except IOError:
|
|
|
|
raise
|
|
|
|
except Exception:
|
|
|
|
_warn_unhandled_exception()
|
|
|
|
raise LoadError("invalid Netscape format cookies file %r: %r" %
|
2005-12-23 17:24:35 -04:00
|
|
|
(filename, line))
|
2004-05-31 15:22:40 -03:00
|
|
|
|
|
|
|
def save(self, filename=None, ignore_discard=False, ignore_expires=False):
|
|
|
|
if filename is None:
|
|
|
|
if self.filename is not None: filename = self.filename
|
|
|
|
else: raise ValueError(MISSING_FILENAME_TEXT)
|
|
|
|
|
|
|
|
f = open(filename, "w")
|
|
|
|
try:
|
|
|
|
f.write(self.header)
|
|
|
|
now = time.time()
|
|
|
|
for cookie in self:
|
|
|
|
if not ignore_discard and cookie.discard:
|
|
|
|
continue
|
|
|
|
if not ignore_expires and cookie.is_expired(now):
|
|
|
|
continue
|
|
|
|
if cookie.secure: secure = "TRUE"
|
|
|
|
else: secure = "FALSE"
|
|
|
|
if cookie.domain.startswith("."): initial_dot = "TRUE"
|
|
|
|
else: initial_dot = "FALSE"
|
|
|
|
if cookie.expires is not None:
|
|
|
|
expires = str(cookie.expires)
|
|
|
|
else:
|
|
|
|
expires = ""
|
|
|
|
if cookie.value is None:
|
|
|
|
# cookies.txt regards 'Set-Cookie: foo' as a cookie
|
|
|
|
# with no name, whereas cookielib regards it as a
|
|
|
|
# cookie with no value.
|
|
|
|
name = ""
|
|
|
|
value = cookie.name
|
|
|
|
else:
|
|
|
|
name = cookie.name
|
|
|
|
value = cookie.value
|
|
|
|
f.write(
|
|
|
|
"\t".join([cookie.domain, initial_dot, cookie.path,
|
|
|
|
secure, expires, name, value])+
|
|
|
|
"\n")
|
|
|
|
finally:
|
|
|
|
f.close()
|