diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py index 6694f5478bdadf..86f4dca241e6b5 100644 --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -131,6 +131,7 @@ # import re import string +import http.cookiejar __all__ = ["CookieError", "BaseCookie", "SimpleCookie"] @@ -420,37 +421,6 @@ def OutputString(self, attrs=None): return _semispacejoin(result) -# -# Pattern for finding cookie -# -# This used to be strict parsing based on the RFC2109 and RFC2068 -# specifications. I have since discovered that MSIE 3.0x doesn't -# follow the character rules outlined in those specs. As a -# result, the parsing rules here are less strict. -# - -_LegalKeyChars = r"\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=" -_LegalValueChars = _LegalKeyChars + r'\[\]' -_CookiePattern = re.compile(r""" - \s* # Optional whitespace at start of cookie - (?P # Start of group 'key' - [""" + _LegalKeyChars + r"""]+? # Any word of at least one letter - ) # End of group 'key' - ( # Optional group: there may not be a value. - \s*=\s* # Equal Sign - (?P # Start of group 'val' - "(?:[^\\"]|\\.)*" # Any doublequoted string - | # or - \w{3},\s[\w\d\s-]{9,11}\s[\d:]{8}\sGMT # Special case for "expires" attr - | # or - [""" + _LegalValueChars + r"""]* # Any word or empty string - ) # End of group 'val' - )? # End of optional value group - \s* # Any number of spaces. - (\s+|;|$) # Ending either at space, semicolon, or EOS. - """, re.ASCII | re.VERBOSE) # re.ASCII may be removed if safe. - - # At long last, here is the cookie class. Using this class is almost just like # using a dictionary. See this module's docstring for example usage. # @@ -533,9 +503,7 @@ def load(self, rawdata): self[key] = value return - def __parse_string(self, str, patt=_CookiePattern): - i = 0 # Our starting point - n = len(str) # Length of string + def __parse_string(self, rawstr): parsed_items = [] # Parsed (type, key, value) triples morsel_seen = False # A key=value pair was previously encountered @@ -545,16 +513,11 @@ def __parse_string(self, str, patt=_CookiePattern): # We first parse the whole cookie string and reject it if it's # syntactically invalid (this helps avoid some classes of injection # attacks). - while 0 <= i < n: - # Start looking for a cookie - match = patt.match(str, i) - if not match: - # No more cookies - break - - key, value = match.group("key"), match.group("val") - i = match.end(0) - + for key, value in http.cookiejar.parse_ns_headers([rawstr,])[0]: + if key == 'version': + continue + if not isinstance(value, str): + value = str(value) if key[0] == "$": if not morsel_seen: # We ignore attributes which pertain to the cookie diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py index 6072c7e15e92be..c441c96a24c7a8 100644 --- a/Lib/test/test_http_cookies.py +++ b/Lib/test/test_http_cookies.py @@ -16,11 +16,6 @@ def test_basic(self): 'repr': "", 'output': 'Set-Cookie: chips=ahoy\nSet-Cookie: vienna=finger'}, - {'data': 'keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"', - 'dict': {'keebler' : 'E=mc2; L="Loves"; fudge=\012;'}, - 'repr': '''''', - 'output': 'Set-Cookie: keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'}, - # Check illegal cookies that have an '=' char in an unquoted value {'data': 'keebler=E=mc2', 'dict': {'keebler' : 'E=mc2'}, @@ -47,7 +42,20 @@ def test_basic(self): 'Set-Cookie: d=r', 'Set-Cookie: f=h' )) - } + }, + # issue35824 - http.cookies._CookiePattern modifying regular expressions + { + 'data': 'Hello=World; Expires=Thu, 31 Jan 2019 05:56:00 GMT;', + 'dict': {'Hello': 'World'}, + 'repr': "", + 'output': 'Set-Cookie: Hello=World; expires=Thu, 31 Jan 2019 05:56:00 GMT' + }, + { + 'data': 'Hello=World; Expires=Thu,31 Jan 2019 05:56:00 GMT;', + 'dict': {'Hello': 'World'}, + 'repr': "", + 'output': 'Set-Cookie: Hello=World; expires=Thu,31 Jan 2019 05:56:00 GMT' + }, ] for case in cases: diff --git a/Misc/ACKS b/Misc/ACKS index 81b51f75199159..94ac83610cbfa7 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -622,6 +622,7 @@ Manus Hand Milton L. Hankins Stephen Hansen Barry Hantman +Zehao Hao Lynda Hardman Bar Harel Derek Harland diff --git a/Misc/NEWS.d/next/Library/2019-01-27-05-27-23.bpo-35824.gMGwan.rst b/Misc/NEWS.d/next/Library/2019-01-27-05-27-23.bpo-35824.gMGwan.rst new file mode 100644 index 00000000000000..3ee0e6489c9c96 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-01-27-05-27-23.bpo-35824.gMGwan.rst @@ -0,0 +1 @@ +Modify the parsing of Expires in Set-Cookie, Spaces and commas are both treated as delimiters. Patch by MeiK. \ No newline at end of file