mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	gh-95087: Fix IndexError in parsing invalid date in the email module (GH-95201)
Co-authored-by: wouter bolsterlee <wouter@bolsterl.ee>
This commit is contained in:
		
							parent
							
								
									5956de16cd
								
							
						
					
					
						commit
						ea5ed0ba51
					
				
					 4 changed files with 60 additions and 23 deletions
				
			
		| 
						 | 
					@ -95,6 +95,8 @@ def _parsedate_tz(data):
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
    data = data[:5]
 | 
					    data = data[:5]
 | 
				
			||||||
    [dd, mm, yy, tm, tz] = data
 | 
					    [dd, mm, yy, tm, tz] = data
 | 
				
			||||||
 | 
					    if not (dd and mm and yy):
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
    mm = mm.lower()
 | 
					    mm = mm.lower()
 | 
				
			||||||
    if mm not in _monthnames:
 | 
					    if mm not in _monthnames:
 | 
				
			||||||
        dd, mm = mm, dd.lower()
 | 
					        dd, mm = mm, dd.lower()
 | 
				
			||||||
| 
						 | 
					@ -110,6 +112,8 @@ def _parsedate_tz(data):
 | 
				
			||||||
        yy, tm = tm, yy
 | 
					        yy, tm = tm, yy
 | 
				
			||||||
    if yy[-1] == ',':
 | 
					    if yy[-1] == ',':
 | 
				
			||||||
        yy = yy[:-1]
 | 
					        yy = yy[:-1]
 | 
				
			||||||
 | 
					        if not yy:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
    if not yy[0].isdigit():
 | 
					    if not yy[0].isdigit():
 | 
				
			||||||
        yy, tz = tz, yy
 | 
					        yy, tz = tz, yy
 | 
				
			||||||
    if tm[-1] == ',':
 | 
					    if tm[-1] == ',':
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3047,33 +3047,43 @@ def test_formatdate_usegmt(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # parsedate and parsedate_tz will become deprecated interfaces someday
 | 
					    # parsedate and parsedate_tz will become deprecated interfaces someday
 | 
				
			||||||
    def test_parsedate_returns_None_for_invalid_strings(self):
 | 
					    def test_parsedate_returns_None_for_invalid_strings(self):
 | 
				
			||||||
        self.assertIsNone(utils.parsedate(''))
 | 
					        # See also test_parsedate_to_datetime_with_invalid_raises_valueerror
 | 
				
			||||||
        self.assertIsNone(utils.parsedate_tz(''))
 | 
					        # in test_utils.
 | 
				
			||||||
        self.assertIsNone(utils.parsedate(' '))
 | 
					        invalid_dates = [
 | 
				
			||||||
        self.assertIsNone(utils.parsedate_tz(' '))
 | 
					            '',
 | 
				
			||||||
        self.assertIsNone(utils.parsedate('0'))
 | 
					            ' ',
 | 
				
			||||||
        self.assertIsNone(utils.parsedate_tz('0'))
 | 
					            '0',
 | 
				
			||||||
        self.assertIsNone(utils.parsedate('A Complete Waste of Time'))
 | 
					            'A Complete Waste of Time',
 | 
				
			||||||
        self.assertIsNone(utils.parsedate_tz('A Complete Waste of Time'))
 | 
					            'Wed, 3 Apr 2002 12.34.56.78+0800',
 | 
				
			||||||
        self.assertIsNone(utils.parsedate_tz('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:
 | 
					        # Not a part of the spec but, but this has historically worked:
 | 
				
			||||||
        self.assertIsNone(utils.parsedate(None))
 | 
					        self.assertIsNone(utils.parsedate(None))
 | 
				
			||||||
        self.assertIsNone(utils.parsedate_tz(None))
 | 
					        self.assertIsNone(utils.parsedate_tz(None))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_parsedate_compact(self):
 | 
					    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
 | 
					        # The FWS after the comma is optional
 | 
				
			||||||
        self.assertEqual(utils.parsedate('Wed,3 Apr 2002 14:58:26 +0800'),
 | 
					        self.assertEqual(utils.parsedate_tz('Wed,3 Apr 2002 14:58:26 +0800'),
 | 
				
			||||||
                         utils.parsedate('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):
 | 
					    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 = self.assertEqual
 | 
				
			||||||
        eq(utils.parsedate_tz('5 Feb 2003 13:47:26 -0800'),
 | 
					        eq(utils.parsedate_tz('5 Feb 2003 13:47:26 -0800'),
 | 
				
			||||||
           (2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800))
 | 
					           (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):
 | 
					    def test_parsedate_no_space_before_positive_offset(self):
 | 
				
			||||||
        self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26+0800'),
 | 
					        self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26+0800'),
 | 
				
			||||||
| 
						 | 
					@ -3084,7 +3094,6 @@ def test_parsedate_no_space_before_negative_offset(self):
 | 
				
			||||||
        self.assertEqual(utils.parsedate_tz('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))
 | 
					           (2002, 4, 3, 14, 58, 26, 0, 1, -1, -28800))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_parsedate_accepts_time_with_dots(self):
 | 
					    def test_parsedate_accepts_time_with_dots(self):
 | 
				
			||||||
        eq = self.assertEqual
 | 
					        eq = self.assertEqual
 | 
				
			||||||
        eq(utils.parsedate_tz('5 Feb 2003 13.47.26 -0800'),
 | 
					        eq(utils.parsedate_tz('5 Feb 2003 13.47.26 -0800'),
 | 
				
			||||||
| 
						 | 
					@ -3092,6 +3101,20 @@ def test_parsedate_accepts_time_with_dots(self):
 | 
				
			||||||
        eq(utils.parsedate_tz('5 Feb 2003 13.47 -0800'),
 | 
					        eq(utils.parsedate_tz('5 Feb 2003 13.47 -0800'),
 | 
				
			||||||
           (2003, 2, 5, 13, 47, 0, 0, 1, -1, -28800))
 | 
					           (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):
 | 
					    def test_parsedate_acceptable_to_time_functions(self):
 | 
				
			||||||
        eq = self.assertEqual
 | 
					        eq = self.assertEqual
 | 
				
			||||||
        timetup = utils.parsedate('5 Feb 2003 13:47:26 -0800')
 | 
					        timetup = utils.parsedate('5 Feb 2003 13:47:26 -0800')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,12 +49,21 @@ def test_parsedate_to_datetime_naive(self):
 | 
				
			||||||
            self.naive_dt)
 | 
					            self.naive_dt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_parsedate_to_datetime_with_invalid_raises_valueerror(self):
 | 
					    def test_parsedate_to_datetime_with_invalid_raises_valueerror(self):
 | 
				
			||||||
        invalid_dates = ['',
 | 
					        # See also test_parsedate_returns_None_for_invalid_strings in test_email.
 | 
				
			||||||
 | 
					        invalid_dates = [
 | 
				
			||||||
 | 
					            '',
 | 
				
			||||||
 | 
					            ' ',
 | 
				
			||||||
            '0',
 | 
					            '0',
 | 
				
			||||||
                         'A Complete Waste of Time'
 | 
					            '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 27:39:33 +0600',
 | 
				
			||||||
            'Tue, 06 Jun 2017 07:39:33 +2600',
 | 
					            'Tue, 06 Jun 2017 07:39:33 +2600',
 | 
				
			||||||
                         'Tue, 06 Jun 2017 27:39:33']
 | 
					            '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:
 | 
					        for dtstr in invalid_dates:
 | 
				
			||||||
            with self.subTest(dtstr=dtstr):
 | 
					            with self.subTest(dtstr=dtstr):
 | 
				
			||||||
                self.assertRaises(ValueError, utils.parsedate_to_datetime, dtstr)
 | 
					                self.assertRaises(ValueError, utils.parsedate_to_datetime, dtstr)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					Fix IndexError in parsing invalid date in the :mod:`email` module.
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue