| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -74,19 +74,25 @@ def _parseparam(s): | |||
| 74 | 74 | # RDM This might be a Header, so for now stringify it. | |
| 75 | 75 | s = ';' + str(s) | |
| 76 | 76 | plist = [] | |
| 77 | - while s[:1] == ';': | ||
| 78 | - s = s[1:] | ||
| 79 | - end = s.find(';') | ||
| 80 | - while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2: | ||
| 81 | - end = s.find(';', end + 1) | ||
| 77 | + start = 0 | ||
| 78 | + while s.find(';', start) == start: | ||
| 79 | + start += 1 | ||
| 80 | + end = s.find(';', start) | ||
| 81 | + ind, diff = start, 0 | ||
| 82 | + while end > 0: | ||
| 83 | + diff += s.count('"', ind, end) - s.count('\\"', ind, end) | ||
| 84 | + if diff % 2 == 0: | ||
| 85 | + break | ||
| 86 | + end, ind = ind, s.find(';', end + 1) | ||
| 82 | 87 | if end < 0: | |
| 83 | 88 | end = len(s) | |
| 84 | - f = s[:end] | ||
| 85 | - if '=' in f: | ||
| 86 | - i = f.index('=') | ||
| 87 | - f = f[:i].strip().lower() + '=' + f[i+1:].strip() | ||
| 89 | + i = s.find('=', start, end) | ||
| 90 | + if i == -1: | ||
| 91 | + f = s[start:end] | ||
| 92 | + else: | ||
| 93 | + f = s[start:i].rstrip().lower() + '=' + s[i+1:end].lstrip() | ||
| 88 | 94 | plist.append(f.strip()) | |
| 89 | - s = s[end:] | ||
| 95 | + start = end | ||
| 90 | 96 | return plist | |
| 91 | 97 | ||
| 92 | 98 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -445,6 +445,27 @@ def test_get_param_with_quotes(self): | |||
| 445 | 445 | "Content-Type: foo; bar*0=\"baz\\\"foobar\"; bar*1=\"\\\"baz\"") | |
| 446 | 446 | self.assertEqual(msg.get_param('bar'), 'baz"foobar"baz') | |
| 447 | 447 | ||
| 448 | + def test_get_param_linear_complexity(self): | ||
| 449 | + # Ensure that email.message._parseparam() is fast. | ||
| 450 | + # See https://github.com/python/cpython/issues/136063. | ||
| 451 | + N = 100_000 | ||
| 452 | + for s, r in [ | ||
| 453 | + ("", ""), | ||
| 454 | + ("foo=bar", "foo=bar"), | ||
| 455 | + (" FOO = bar ", "foo=bar"), | ||
| 456 | + ]: | ||
| 457 | + with self.subTest(s=s, r=r, N=N): | ||
| 458 | + src = f'{s};' * (N - 1) + s | ||
| 459 | + res = email.message._parseparam(src) | ||
| 460 | + self.assertEqual(len(res), N) | ||
| 461 | + self.assertEqual(len(set(res)), 1) | ||
| 462 | + self.assertEqual(res[0], r) | ||
| 463 | + | ||
| 464 | + # This will be considered as a single parameter. | ||
| 465 | + malformed = 's="' + ';' * (N - 1) | ||
| 466 | + res = email.message._parseparam(malformed) | ||
| 467 | + self.assertEqual(res, [malformed]) | ||
| 468 | + | ||
| 448 | 469 | def test_field_containment(self): | |
| 449 | 470 | msg = email.message_from_string('Header: exists') | |
| 450 | 471 | self.assertIn('header', msg) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + :mod:`email.message`: ensure linear complexity for legacy HTTP parameters | ||
| 2 | + parsing. Patch by Bénédikt Tran. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments