Skip to content

Commit 94eb1e9

Browse files
gh-95087: Fix IndexError in parsing invalid date in the email module (GH-95201)
Co-authored-by: wouter bolsterlee <[email protected]> (cherry picked from commit ea5ed0b) Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent 40f41ba commit 94eb1e9

File tree

4 files changed

+60
-23
lines changed

4 files changed

+60
-23
lines changed

Lib/email/_parseaddr.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ def _parsedate_tz(data):
9595
return None
9696
data = data[:5]
9797
[dd, mm, yy, tm, tz] = data
98+
if not (dd and mm and yy):
99+
return None
98100
mm = mm.lower()
99101
if mm not in _monthnames:
100102
dd, mm = mm, dd.lower()
@@ -110,6 +112,8 @@ def _parsedate_tz(data):
110112
yy, tm = tm, yy
111113
if yy[-1] == ',':
112114
yy = yy[:-1]
115+
if not yy:
116+
return None
113117
if not yy[0].isdigit():
114118
yy, tz = tz, yy
115119
if tm[-1] == ',':

Lib/test/test_email/test_email.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3016,33 +3016,43 @@ def test_formatdate_usegmt(self):
30163016

30173017
# parsedate and parsedate_tz will become deprecated interfaces someday
30183018
def test_parsedate_returns_None_for_invalid_strings(self):
3019-
self.assertIsNone(utils.parsedate(''))
3020-
self.assertIsNone(utils.parsedate_tz(''))
3021-
self.assertIsNone(utils.parsedate(' '))
3022-
self.assertIsNone(utils.parsedate_tz(' '))
3023-
self.assertIsNone(utils.parsedate('0'))
3024-
self.assertIsNone(utils.parsedate_tz('0'))
3025-
self.assertIsNone(utils.parsedate('A Complete Waste of Time'))
3026-
self.assertIsNone(utils.parsedate_tz('A Complete Waste of Time'))
3027-
self.assertIsNone(utils.parsedate_tz('Wed, 3 Apr 2002 12.34.56.78+0800'))
3019+
# See also test_parsedate_to_datetime_with_invalid_raises_valueerror
3020+
# in test_utils.
3021+
invalid_dates = [
3022+
'',
3023+
' ',
3024+
'0',
3025+
'A Complete Waste of Time',
3026+
'Wed, 3 Apr 2002 12.34.56.78+0800',
3027+
'17 June , 2022',
3028+
'Friday, -Nov-82 16:14:55 EST',
3029+
'Friday, Nov--82 16:14:55 EST',
3030+
'Friday, 19-Nov- 16:14:55 EST',
3031+
]
3032+
for dtstr in invalid_dates:
3033+
with self.subTest(dtstr=dtstr):
3034+
self.assertIsNone(utils.parsedate(dtstr))
3035+
self.assertIsNone(utils.parsedate_tz(dtstr))
30283036
# Not a part of the spec but, but this has historically worked:
30293037
self.assertIsNone(utils.parsedate(None))
30303038
self.assertIsNone(utils.parsedate_tz(None))
30313039

30323040
def test_parsedate_compact(self):
3041+
self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26 +0800'),
3042+
(2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800))
30333043
# The FWS after the comma is optional
3034-
self.assertEqual(utils.parsedate('Wed,3 Apr 2002 14:58:26 +0800'),
3035-
utils.parsedate('Wed, 3 Apr 2002 14:58:26 +0800'))
3044+
self.assertEqual(utils.parsedate_tz('Wed,3 Apr 2002 14:58:26 +0800'),
3045+
(2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800))
3046+
# The comma is optional
3047+
self.assertEqual(utils.parsedate_tz('Wed 3 Apr 2002 14:58:26 +0800'),
3048+
(2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800))
30363049

30373050
def test_parsedate_no_dayofweek(self):
3038-
eq = self.assertEqual
3039-
eq(utils.parsedate_tz('25 Feb 2003 13:47:26 -0800'),
3040-
(2003, 2, 25, 13, 47, 26, 0, 1, -1, -28800))
3041-
3042-
def test_parsedate_compact_no_dayofweek(self):
30433051
eq = self.assertEqual
30443052
eq(utils.parsedate_tz('5 Feb 2003 13:47:26 -0800'),
30453053
(2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800))
3054+
eq(utils.parsedate_tz('February 5, 2003 13:47:26 -0800'),
3055+
(2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800))
30463056

30473057
def test_parsedate_no_space_before_positive_offset(self):
30483058
self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26+0800'),
@@ -3053,14 +3063,27 @@ def test_parsedate_no_space_before_negative_offset(self):
30533063
self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26-0800'),
30543064
(2002, 4, 3, 14, 58, 26, 0, 1, -1, -28800))
30553065

3056-
30573066
def test_parsedate_accepts_time_with_dots(self):
30583067
eq = self.assertEqual
30593068
eq(utils.parsedate_tz('5 Feb 2003 13.47.26 -0800'),
30603069
(2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800))
30613070
eq(utils.parsedate_tz('5 Feb 2003 13.47 -0800'),
30623071
(2003, 2, 5, 13, 47, 0, 0, 1, -1, -28800))
30633072

3073+
def test_parsedate_rfc_850(self):
3074+
self.assertEqual(utils.parsedate_tz('Friday, 19-Nov-82 16:14:55 EST'),
3075+
(1982, 11, 19, 16, 14, 55, 0, 1, -1, -18000))
3076+
3077+
def test_parsedate_no_seconds(self):
3078+
self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58 +0800'),
3079+
(2002, 4, 3, 14, 58, 0, 0, 1, -1, 28800))
3080+
3081+
def test_parsedate_dot_time_delimiter(self):
3082+
self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14.58.26 +0800'),
3083+
(2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800))
3084+
self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14.58 +0800'),
3085+
(2002, 4, 3, 14, 58, 0, 0, 1, -1, 28800))
3086+
30643087
def test_parsedate_acceptable_to_time_functions(self):
30653088
eq = self.assertEqual
30663089
timetup = utils.parsedate('5 Feb 2003 13:47:26 -0800')

Lib/test/test_email/test_utils.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,21 @@ def test_parsedate_to_datetime_naive(self):
4949
self.naive_dt)
5050

5151
def test_parsedate_to_datetime_with_invalid_raises_valueerror(self):
52-
invalid_dates = ['',
53-
'0',
54-
'A Complete Waste of Time'
55-
'Tue, 06 Jun 2017 27:39:33 +0600',
56-
'Tue, 06 Jun 2017 07:39:33 +2600',
57-
'Tue, 06 Jun 2017 27:39:33']
52+
# See also test_parsedate_returns_None_for_invalid_strings in test_email.
53+
invalid_dates = [
54+
'',
55+
' ',
56+
'0',
57+
'A Complete Waste of Time',
58+
'Wed, 3 Apr 2002 12.34.56.78+0800'
59+
'Tue, 06 Jun 2017 27:39:33 +0600',
60+
'Tue, 06 Jun 2017 07:39:33 +2600',
61+
'Tue, 06 Jun 2017 27:39:33',
62+
'17 June , 2022',
63+
'Friday, -Nov-82 16:14:55 EST',
64+
'Friday, Nov--82 16:14:55 EST',
65+
'Friday, 19-Nov- 16:14:55 EST',
66+
]
5867
for dtstr in invalid_dates:
5968
with self.subTest(dtstr=dtstr):
6069
self.assertRaises(ValueError, utils.parsedate_to_datetime, dtstr)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix IndexError in parsing invalid date in the :mod:`email` module.

0 commit comments

Comments
 (0)