Skip to content

Commit 7c3bc5e

Browse files
authored
Update test_http_cookies.py from 3.13.11 (RustPython#6481)
* Update `test_http_cookies.py` from 3.13.11 * Mark failing test * Update `http/cookies.py` from 3.13.11 * Unmark passing test * Lower amount
1 parent 9d14776 commit 7c3bc5e

2 files changed

Lines changed: 108 additions & 36 deletions

File tree

Lib/http/cookies.py

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,13 @@ def _quote(str):
184184
return '"' + str.translate(_Translator) + '"'
185185

186186

187-
_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
188-
_QuotePatt = re.compile(r"[\\].")
187+
_unquote_sub = re.compile(r'\\(?:([0-3][0-7][0-7])|(.))').sub
188+
189+
def _unquote_replace(m):
190+
if m[1]:
191+
return chr(int(m[1], 8))
192+
else:
193+
return m[2]
189194

190195
def _unquote(str):
191196
# If there aren't any doublequotes,
@@ -205,36 +210,13 @@ def _unquote(str):
205210
# \012 --> \n
206211
# \" --> "
207212
#
208-
i = 0
209-
n = len(str)
210-
res = []
211-
while 0 <= i < n:
212-
o_match = _OctalPatt.search(str, i)
213-
q_match = _QuotePatt.search(str, i)
214-
if not o_match and not q_match: # Neither matched
215-
res.append(str[i:])
216-
break
217-
# else:
218-
j = k = -1
219-
if o_match:
220-
j = o_match.start(0)
221-
if q_match:
222-
k = q_match.start(0)
223-
if q_match and (not o_match or k < j): # QuotePatt matched
224-
res.append(str[i:k])
225-
res.append(str[k+1])
226-
i = k + 2
227-
else: # OctalPatt matched
228-
res.append(str[i:j])
229-
res.append(chr(int(str[j+1:j+4], 8)))
230-
i = j + 4
231-
return _nulljoin(res)
213+
return _unquote_sub(_unquote_replace, str)
232214

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

240222
_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
@@ -442,9 +424,11 @@ def OutputString(self, attrs=None):
442424
( # Optional group: there may not be a value.
443425
\s*=\s* # Equal Sign
444426
(?P<val> # Start of group 'val'
445-
"(?:[^\\"]|\\.)*" # Any doublequoted string
427+
"(?:[^\\"]|\\.)*" # Any double-quoted string
446428
| # or
447-
\w{3},\s[\w\d\s-]{9,11}\s[\d:]{8}\sGMT # Special case for "expires" attr
429+
# Special case for "expires" attr
430+
(\w{3,6}day|\w{3}),\s # Day of the week or abbreviated day
431+
[\w\d\s-]{9,11}\s[\d:]{8}\sGMT # Date and time in specific format
448432
| # or
449433
[""" + _LegalValueChars + r"""]* # Any word or empty string
450434
) # End of group 'val'

Lib/test/test_http_cookies.py

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
# Simple test suite for http/cookies.py
22

33
import copy
4-
from test.support import run_unittest, run_doctest
54
import unittest
5+
import doctest
66
from http import cookies
77
import pickle
8+
from test import support
9+
from test.support.testcase import ExtraAssertions
810

911

10-
class CookieTests(unittest.TestCase):
12+
class CookieTests(unittest.TestCase, ExtraAssertions):
1113

1214
def test_basic(self):
1315
cases = [
@@ -58,6 +60,90 @@ def test_basic(self):
5860
for k, v in sorted(case['dict'].items()):
5961
self.assertEqual(C[k].value, v)
6062

63+
def test_obsolete_rfc850_date_format(self):
64+
# Test cases with different days and dates in obsolete RFC 850 format
65+
test_cases = [
66+
# from RFC 850, change EST to GMT
67+
# https://datatracker.ietf.org/doc/html/rfc850#section-2
68+
{
69+
'data': 'key=value; expires=Saturday, 01-Jan-83 00:00:00 GMT',
70+
'output': 'Saturday, 01-Jan-83 00:00:00 GMT'
71+
},
72+
{
73+
'data': 'key=value; expires=Friday, 19-Nov-82 16:59:30 GMT',
74+
'output': 'Friday, 19-Nov-82 16:59:30 GMT'
75+
},
76+
# from RFC 9110
77+
# https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6.7-6
78+
{
79+
'data': 'key=value; expires=Sunday, 06-Nov-94 08:49:37 GMT',
80+
'output': 'Sunday, 06-Nov-94 08:49:37 GMT'
81+
},
82+
# other test cases
83+
{
84+
'data': 'key=value; expires=Wednesday, 09-Nov-94 08:49:37 GMT',
85+
'output': 'Wednesday, 09-Nov-94 08:49:37 GMT'
86+
},
87+
{
88+
'data': 'key=value; expires=Friday, 11-Nov-94 08:49:37 GMT',
89+
'output': 'Friday, 11-Nov-94 08:49:37 GMT'
90+
},
91+
{
92+
'data': 'key=value; expires=Monday, 14-Nov-94 08:49:37 GMT',
93+
'output': 'Monday, 14-Nov-94 08:49:37 GMT'
94+
},
95+
]
96+
97+
for case in test_cases:
98+
with self.subTest(data=case['data']):
99+
C = cookies.SimpleCookie()
100+
C.load(case['data'])
101+
102+
# Extract the cookie name from the data string
103+
cookie_name = case['data'].split('=')[0]
104+
105+
# Check if the cookie is loaded correctly
106+
self.assertIn(cookie_name, C)
107+
self.assertEqual(C[cookie_name].get('expires'), case['output'])
108+
109+
def test_unquote(self):
110+
cases = [
111+
(r'a="b=\""', 'b="'),
112+
(r'a="b=\\"', 'b=\\'),
113+
(r'a="b=\="', 'b=='),
114+
(r'a="b=\n"', 'b=n'),
115+
(r'a="b=\042"', 'b="'),
116+
(r'a="b=\134"', 'b=\\'),
117+
(r'a="b=\377"', 'b=\xff'),
118+
(r'a="b=\400"', 'b=400'),
119+
(r'a="b=\42"', 'b=42'),
120+
(r'a="b=\\042"', 'b=\\042'),
121+
(r'a="b=\\134"', 'b=\\134'),
122+
(r'a="b=\\\""', 'b=\\"'),
123+
(r'a="b=\\\042"', 'b=\\"'),
124+
(r'a="b=\134\""', 'b=\\"'),
125+
(r'a="b=\134\042"', 'b=\\"'),
126+
]
127+
for encoded, decoded in cases:
128+
with self.subTest(encoded):
129+
C = cookies.SimpleCookie()
130+
C.load(encoded)
131+
self.assertEqual(C['a'].value, decoded)
132+
133+
@support.requires_resource('cpu')
134+
def test_unquote_large(self):
135+
#n = 10**6
136+
n = 10**4 # XXX: RUSTPYTHON; This takes more than 10 minutes to run. lower to 4
137+
for encoded in r'\\', r'\134':
138+
with self.subTest(encoded):
139+
data = 'a="b=' + encoded*n + ';"'
140+
C = cookies.SimpleCookie()
141+
C.load(data)
142+
value = C['a'].value
143+
self.assertEqual(value[:3], 'b=\\')
144+
self.assertEqual(value[-2:], '\\;')
145+
self.assertEqual(len(value), n + 3)
146+
61147
def test_load(self):
62148
C = cookies.SimpleCookie()
63149
C.load('Customer="WILE_E_COYOTE"; Version=1; Path=/acme')
@@ -96,7 +182,7 @@ def test_special_attrs(self):
96182
C = cookies.SimpleCookie('Customer="WILE_E_COYOTE"')
97183
C['Customer']['expires'] = 0
98184
# can't test exact output, it always depends on current date/time
99-
self.assertTrue(C.output().endswith('GMT'))
185+
self.assertEndsWith(C.output(), 'GMT')
100186

101187
# loading 'expires'
102188
C = cookies.SimpleCookie()
@@ -479,9 +565,11 @@ def test_repr(self):
479565
r'Set-Cookie: key=coded_val; '
480566
r'expires=\w+, \d+ \w+ \d+ \d+:\d+:\d+ \w+')
481567

482-
def test_main():
483-
run_unittest(CookieTests, MorselTests)
484-
run_doctest(cookies)
568+
569+
def load_tests(loader, tests, pattern):
570+
tests.addTest(doctest.DocTestSuite(cookies))
571+
return tests
572+
485573

486574
if __name__ == '__main__':
487-
test_main()
575+
unittest.main()

0 commit comments

Comments
 (0)