[Python-checkins] gh-95087: Fix IndexError in parsing invalid date in the email module (GH-95201)

miss-islington webhook-mailer at python.org
Mon Jul 25 02:39:10 EDT 2022


https://github.com/python/cpython/commit/94eb1e9789eacf855919cddade7d7d0d26b4f08d
commit: 94eb1e9789eacf855919cddade7d7d0d26b4f08d
branch: 3.10
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2022-07-24T23:39:00-07:00
summary:

gh-95087: Fix IndexError in parsing invalid date in the email module (GH-95201)


Co-authored-by: wouter bolsterlee <wouter at bolsterl.ee>
(cherry picked from commit ea5ed0ba51c10cfdde7651a475438551964dfdfc)

Co-authored-by: Serhiy Storchaka <storchaka at gmail.com>

files:
A Misc/NEWS.d/next/Library/2022-07-24-12-59-02.gh-issue-95087.VvqXkN.rst
M Lib/email/_parseaddr.py
M Lib/test/test_email/test_email.py
M Lib/test/test_email/test_utils.py

diff --git a/Lib/email/_parseaddr.py b/Lib/email/_parseaddr.py
index ba5ad5a36d06b..febe411355d6b 100644
--- a/Lib/email/_parseaddr.py
+++ b/Lib/email/_parseaddr.py
@@ -95,6 +95,8 @@ def _parsedate_tz(data):
         return None
     data = data[:5]
     [dd, mm, yy, tm, tz] = data
+    if not (dd and mm and yy):
+        return None
     mm = mm.lower()
     if mm not in _monthnames:
         dd, mm = mm, dd.lower()
@@ -110,6 +112,8 @@ def _parsedate_tz(data):
         yy, tm = tm, yy
     if yy[-1] == ',':
         yy = yy[:-1]
+        if not yy:
+            return None
     if not yy[0].isdigit():
         yy, tz = tz, yy
     if tm[-1] == ',':
diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py
index 3a5663ac01d0f..8b16cca9bf543 100644
--- a/Lib/test/test_email/test_email.py
+++ b/Lib/test/test_email/test_email.py
@@ -3016,33 +3016,43 @@ def test_formatdate_usegmt(self):
 
     # parsedate and parsedate_tz will become deprecated interfaces someday
     def test_parsedate_returns_None_for_invalid_strings(self):
-        self.assertIsNone(utils.parsedate(''))
-        self.assertIsNone(utils.parsedate_tz(''))
-        self.assertIsNone(utils.parsedate(' '))
-        self.assertIsNone(utils.parsedate_tz(' '))
-        self.assertIsNone(utils.parsedate('0'))
-        self.assertIsNone(utils.parsedate_tz('0'))
-        self.assertIsNone(utils.parsedate('A Complete Waste of Time'))
-        self.assertIsNone(utils.parsedate_tz('A Complete Waste of Time'))
-        self.assertIsNone(utils.parsedate_tz('Wed, 3 Apr 2002 12.34.56.78+0800'))
+        # See also test_parsedate_to_datetime_with_invalid_raises_valueerror
+        # in test_utils.
+        invalid_dates = [
+            '',
+            ' ',
+            '0',
+            'A Complete Waste of Time',
+            'Wed, 3 Apr 2002 12.34.56.78+0800',
+            '17 June , 2022',
+            'Friday, -Nov-82 16:14:55 EST',
+            'Friday, Nov--82 16:14:55 EST',
+            'Friday, 19-Nov- 16:14:55 EST',
+        ]
+        for dtstr in invalid_dates:
+            with self.subTest(dtstr=dtstr):
+                self.assertIsNone(utils.parsedate(dtstr))
+                self.assertIsNone(utils.parsedate_tz(dtstr))
         # Not a part of the spec but, but this has historically worked:
         self.assertIsNone(utils.parsedate(None))
         self.assertIsNone(utils.parsedate_tz(None))
 
     def test_parsedate_compact(self):
+        self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26 +0800'),
+                         (2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800))
         # The FWS after the comma is optional
-        self.assertEqual(utils.parsedate('Wed,3 Apr 2002 14:58:26 +0800'),
-                         utils.parsedate('Wed, 3 Apr 2002 14:58:26 +0800'))
+        self.assertEqual(utils.parsedate_tz('Wed,3 Apr 2002 14:58:26 +0800'),
+                         (2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800))
+        # The comma is optional
+        self.assertEqual(utils.parsedate_tz('Wed 3 Apr 2002 14:58:26 +0800'),
+                         (2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800))
 
     def test_parsedate_no_dayofweek(self):
-        eq = self.assertEqual
-        eq(utils.parsedate_tz('25 Feb 2003 13:47:26 -0800'),
-           (2003, 2, 25, 13, 47, 26, 0, 1, -1, -28800))
-
-    def test_parsedate_compact_no_dayofweek(self):
         eq = self.assertEqual
         eq(utils.parsedate_tz('5 Feb 2003 13:47:26 -0800'),
            (2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800))
+        eq(utils.parsedate_tz('February 5, 2003 13:47:26 -0800'),
+           (2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800))
 
     def test_parsedate_no_space_before_positive_offset(self):
         self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26+0800'),
@@ -3053,7 +3063,6 @@ def test_parsedate_no_space_before_negative_offset(self):
         self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26-0800'),
            (2002, 4, 3, 14, 58, 26, 0, 1, -1, -28800))
 
-
     def test_parsedate_accepts_time_with_dots(self):
         eq = self.assertEqual
         eq(utils.parsedate_tz('5 Feb 2003 13.47.26 -0800'),
@@ -3061,6 +3070,20 @@ def test_parsedate_accepts_time_with_dots(self):
         eq(utils.parsedate_tz('5 Feb 2003 13.47 -0800'),
            (2003, 2, 5, 13, 47, 0, 0, 1, -1, -28800))
 
+    def test_parsedate_rfc_850(self):
+        self.assertEqual(utils.parsedate_tz('Friday, 19-Nov-82 16:14:55 EST'),
+           (1982, 11, 19, 16, 14, 55, 0, 1, -1, -18000))
+
+    def test_parsedate_no_seconds(self):
+        self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58 +0800'),
+                         (2002, 4, 3, 14, 58, 0, 0, 1, -1, 28800))
+
+    def test_parsedate_dot_time_delimiter(self):
+        self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14.58.26 +0800'),
+                         (2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800))
+        self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14.58 +0800'),
+                         (2002, 4, 3, 14, 58, 0, 0, 1, -1, 28800))
+
     def test_parsedate_acceptable_to_time_functions(self):
         eq = self.assertEqual
         timetup = utils.parsedate('5 Feb 2003 13:47:26 -0800')
diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py
index e3d3eaebc9369..78afb358035e8 100644
--- a/Lib/test/test_email/test_utils.py
+++ b/Lib/test/test_email/test_utils.py
@@ -49,12 +49,21 @@ def test_parsedate_to_datetime_naive(self):
             self.naive_dt)
 
     def test_parsedate_to_datetime_with_invalid_raises_valueerror(self):
-        invalid_dates = ['',
-                         '0',
-                         'A Complete Waste of Time'
-                         'Tue, 06 Jun 2017 27:39:33 +0600',
-                         'Tue, 06 Jun 2017 07:39:33 +2600',
-                         'Tue, 06 Jun 2017 27:39:33']
+        # See also test_parsedate_returns_None_for_invalid_strings in test_email.
+        invalid_dates = [
+            '',
+            ' ',
+            '0',
+            'A Complete Waste of Time',
+            'Wed, 3 Apr 2002 12.34.56.78+0800'
+            'Tue, 06 Jun 2017 27:39:33 +0600',
+            'Tue, 06 Jun 2017 07:39:33 +2600',
+            'Tue, 06 Jun 2017 27:39:33',
+            '17 June , 2022',
+            'Friday, -Nov-82 16:14:55 EST',
+            'Friday, Nov--82 16:14:55 EST',
+            'Friday, 19-Nov- 16:14:55 EST',
+        ]
         for dtstr in invalid_dates:
             with self.subTest(dtstr=dtstr):
                 self.assertRaises(ValueError, utils.parsedate_to_datetime, dtstr)
diff --git a/Misc/NEWS.d/next/Library/2022-07-24-12-59-02.gh-issue-95087.VvqXkN.rst b/Misc/NEWS.d/next/Library/2022-07-24-12-59-02.gh-issue-95087.VvqXkN.rst
new file mode 100644
index 0000000000000..48a5c1af74907
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-07-24-12-59-02.gh-issue-95087.VvqXkN.rst
@@ -0,0 +1 @@
+Fix IndexError in parsing invalid date in the :mod:`email` module.



More information about the Python-checkins mailing list