Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 27 additions & 15 deletions Lib/http/cookies.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
_semispacejoin = '; '.join
_spacejoin = ' '.join


#
# Define an exception visible to External modules
#
Expand Down Expand Up @@ -195,12 +196,14 @@ def _quote(str):

_unquote_sub = re.compile(r'\\(?:([0-3][0-7][0-7])|(.))').sub


def _unquote_replace(m):
if m[1]:
return chr(int(m[1], 8))
else:
return m[2]


def _unquote(str):
# If there aren't any doublequotes,
# then there can't be any special characters. See RFC 2109.
Expand All @@ -221,19 +224,22 @@ def _unquote(str):
#
return _unquote_sub(_unquote_replace, str)

# The _getdate() routine is used to set the expiration time in the cookie's HTTP
# header. By default, _getdate() returns the current time in the appropriate
# "expires" format for a Set-Cookie header. The one optional argument is an
# offset from now, in seconds. For example, an offset of -3600 means "one hour
# ago". The offset may be a floating-point number.
# The _getdate() routine is used to set the expiration time in the
# cookie's HTTP header. By default, _getdate() returns the current time
# in the appropriate "expires" format for a Set-Cookie header. The one
# optional argument is an offset from now, in seconds. For example, an
# offset of -3600 means "one hour ago". The offset may be
# a floating-point number.
#


_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']

_monthname = [None,
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']


def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
from time import gmtime, time
now = time()
Expand Down Expand Up @@ -301,18 +307,20 @@ def coded_value(self):

def __setitem__(self, K, V):
K = K.lower()
if not K in self._reserved:
if K not in self._reserved:
raise CookieError("Invalid attribute %r" % (K,))
if _has_control_character(K, V):
raise CookieError(f"Control characters are not allowed in cookies {K!r} {V!r}")
raise CookieError("Control characters are not allowed in " +
f"cookies {K!r} {V!r}")
dict.__setitem__(self, K, V)

def setdefault(self, key, val=None):
key = key.lower()
if key not in self._reserved:
raise CookieError("Invalid attribute %r" % (key,))
if _has_control_character(key, val):
raise CookieError("Control characters are not allowed in cookies %r %r" % (key, val,))
raise CookieError("Control characters are not allowed in " +
f"cookies {key!r} {val!r}")
return dict.setdefault(self, key, val)

def __eq__(self, morsel):
Expand Down Expand Up @@ -350,7 +358,8 @@ def set(self, key, val, coded_val):
raise CookieError('Illegal key %r' % (key,))
if _has_control_character(key, val, coded_val):
raise CookieError(
"Control characters are not allowed in cookies %r %r %r" % (key, val, coded_val,))
"Control characters are not allowed in cookies " +
f"{key!r} {val!r} {coded_val!r}")

# It's a good key, so save it.
self._key = key
Expand Down Expand Up @@ -432,7 +441,7 @@ def OutputString(self, attrs=None):
# result, the parsing rules here are less strict.
#

_LegalKeyChars = r"\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\="
_LegalKeyChars = r"\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\="
_LegalValueChars = _LegalKeyChars + r'\[\]'
_CookiePattern = re.compile(r"""
\s* # Optional whitespace at start of cookie
Expand Down Expand Up @@ -506,18 +515,19 @@ def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
for key, value in items:
value_output = value.output(attrs, header)
if _has_control_character(value_output):
raise CookieError("Control characters are not allowed in cookies")
raise CookieError("Control characters are not allowed " +
"in cookies")
result.append(value_output)
return sep.join(result)

__str__ = output

def __repr__(self):
l = []
t_l = []
items = sorted(self.items())
for key, value in items:
l.append('%s=%s' % (key, repr(value.value)))
return '<%s: %s>' % (self.__class__.__name__, _spacejoin(l))
t_l.append('%s=%s' % (key, repr(value.value)))
return '<%s: %s>' % (self.__class__.__name__, _spacejoin(t_l))

def js_output(self, attrs=None):
"""Return a string suitable for JavaScript."""
Expand Down Expand Up @@ -583,7 +593,8 @@ def __parse_string(self, str, patt=_CookiePattern):
else:
parsed_items.append((TYPE_ATTRIBUTE, key, _unquote(value)))
elif value is not None:
parsed_items.append((TYPE_KEYVALUE, key, self.value_decode(value)))
parsed_items.append((TYPE_KEYVALUE, key,
self.value_decode(value)))
morsel_seen = True
else:
# Invalid cookie string
Expand All @@ -609,6 +620,7 @@ class SimpleCookie(BaseCookie):
calls the builtin str() to convert the value to a string. Values
received from HTTP are kept as strings.
"""

def value_decode(self, val):
return _unquote(val), val

Expand Down
Loading