Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 16ee68d

Browse files
bpo-38976: Add support for HTTP Only flag in MozillaCookieJar (#17471)
Add support for HTTP Only flag in MozillaCookieJar Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
1 parent a3c4cef commit 16ee68d

3 files changed

Lines changed: 35 additions & 14 deletions

File tree

Lib/http/cookiejar.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,18 @@ def _debug(*args):
5050
logger = logging.getLogger("http.cookiejar")
5151
return logger.debug(*args)
5252

53-
53+
HTTPONLY_ATTR = "HTTPOnly"
54+
HTTPONLY_PREFIX = "#HttpOnly_"
5455
DEFAULT_HTTP_PORT = str(http.client.HTTP_PORT)
56+
NETSCAPE_MAGIC_RGX = re.compile("#( Netscape)? HTTP Cookie File")
5557
MISSING_FILENAME_TEXT = ("a filename was not supplied (nor was the CookieJar "
5658
"instance initialised with one)")
59+
NETSCAPE_HEADER_TEXT = """\
60+
# Netscape HTTP Cookie File
61+
# http://curl.haxx.se/rfc/cookie_spec.html
62+
# This is a generated file! Do not edit.
63+
64+
"""
5765

5866
def _warn_unhandled_exception():
5967
# There are a few catch-all except: statements in this module, for
@@ -2004,28 +2012,29 @@ class MozillaCookieJar(FileCookieJar):
20042012
header by default (Mozilla can cope with that).
20052013
20062014
"""
2007-
magic_re = re.compile("#( Netscape)? HTTP Cookie File")
2008-
header = """\
2009-
# Netscape HTTP Cookie File
2010-
# http://curl.haxx.se/rfc/cookie_spec.html
2011-
# This is a generated file! Do not edit.
2012-
2013-
"""
20142015

20152016
def _really_load(self, f, filename, ignore_discard, ignore_expires):
20162017
now = time.time()
20172018

2018-
magic = f.readline()
2019-
if not self.magic_re.search(magic):
2019+
if not NETSCAPE_MAGIC_RGX.match(f.readline()):
20202020
raise LoadError(
20212021
"%r does not look like a Netscape format cookies file" %
20222022
filename)
20232023

20242024
try:
20252025
while 1:
20262026
line = f.readline()
2027+
rest = {}
2028+
20272029
if line == "": break
20282030

2031+
# httponly is a cookie flag as defined in rfc6265
2032+
# when encoded in a netscape cookie file,
2033+
# the line is prepended with "#HttpOnly_"
2034+
if line.startswith(HTTPONLY_PREFIX):
2035+
rest[HTTPONLY_ATTR] = ""
2036+
line = line[len(HTTPONLY_PREFIX):]
2037+
20292038
# last field may be absent, so keep any trailing tab
20302039
if line.endswith("\n"): line = line[:-1]
20312040

@@ -2063,7 +2072,7 @@ def _really_load(self, f, filename, ignore_discard, ignore_expires):
20632072
discard,
20642073
None,
20652074
None,
2066-
{})
2075+
rest)
20672076
if not ignore_discard and c.discard:
20682077
continue
20692078
if not ignore_expires and c.is_expired(now):
@@ -2083,16 +2092,17 @@ def save(self, filename=None, ignore_discard=False, ignore_expires=False):
20832092
else: raise ValueError(MISSING_FILENAME_TEXT)
20842093

20852094
with open(filename, "w") as f:
2086-
f.write(self.header)
2095+
f.write(NETSCAPE_HEADER_TEXT)
20872096
now = time.time()
20882097
for cookie in self:
2098+
domain = cookie.domain
20892099
if not ignore_discard and cookie.discard:
20902100
continue
20912101
if not ignore_expires and cookie.is_expired(now):
20922102
continue
20932103
if cookie.secure: secure = "TRUE"
20942104
else: secure = "FALSE"
2095-
if cookie.domain.startswith("."): initial_dot = "TRUE"
2105+
if domain.startswith("."): initial_dot = "TRUE"
20962106
else: initial_dot = "FALSE"
20972107
if cookie.expires is not None:
20982108
expires = str(cookie.expires)
@@ -2107,7 +2117,9 @@ def save(self, filename=None, ignore_discard=False, ignore_expires=False):
21072117
else:
21082118
name = cookie.name
21092119
value = cookie.value
2120+
if cookie.has_nonstandard_attr(HTTPONLY_ATTR):
2121+
domain = HTTPONLY_PREFIX + domain
21102122
f.write(
2111-
"\t".join([cookie.domain, initial_dot, cookie.path,
2123+
"\t".join([domain, initial_dot, cookie.path,
21122124
secure, expires, name, value])+
21132125
"\n")

Lib/test/test_http_cookiejar.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,6 +1773,10 @@ def test_mozilla(self):
17731773
interact_netscape(c, "http://www.foo.com/",
17741774
"fooc=bar; Domain=www.foo.com; %s" % expires)
17751775

1776+
for cookie in c:
1777+
if cookie.name == "foo1":
1778+
cookie.set_nonstandard_attr("HTTPOnly", "")
1779+
17761780
def save_and_restore(cj, ignore_discard):
17771781
try:
17781782
cj.save(ignore_discard=ignore_discard)
@@ -1787,6 +1791,7 @@ def save_and_restore(cj, ignore_discard):
17871791
new_c = save_and_restore(c, True)
17881792
self.assertEqual(len(new_c), 6) # none discarded
17891793
self.assertIn("name='foo1', value='bar'", repr(new_c))
1794+
self.assertIn("rest={'HTTPOnly': ''}", repr(new_c))
17901795

17911796
new_c = save_and_restore(c, False)
17921797
self.assertEqual(len(new_c), 4) # 2 of them discarded on save
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
The :mod:`http.cookiejar` module now supports the parsing of cookies in CURL-style cookiejar files through MozillaCookieJar
2+
on all platforms. Previously, such cookie entries would be silently ignored when loading a cookiejar with such entries.
3+
4+
Additionally, the HTTP Only attribute is persisted in the object, and will be correctly written to file if the MozillaCookieJar object is subsequently dumped.

0 commit comments

Comments
 (0)