diff --git a/Doc/library/email.util.rst b/Doc/library/email.util.rst index 63fae2ab84e213..63e2ca1bb0e017 100644 --- a/Doc/library/email.util.rst +++ b/Doc/library/email.util.rst @@ -124,7 +124,10 @@ of the new API. .. function:: parsedate_to_datetime(date) The inverse of :func:`format_datetime`. Performs the same function as - :func:`parsedate`, but on success returns a :mod:`~datetime.datetime`. If + :func:`parsedate`, but on success returns a :mod:`~datetime.datetime`; + otherwise ``None`` may be returned if parsing fails, or a ``ValueError`` + raised if *date* contains an invalid value such as an hour greater than + 23 or a timezone offset not between -24 and 24 hours. If the input date has a timezone of ``-0000``, the ``datetime`` will be a naive ``datetime``, and if the date is conforming to the RFCs it will represent a time in UTC but with no indication of the actual source timezone of the diff --git a/Lib/email/errors.py b/Lib/email/errors.py index 791239fa6a54cc..a40e64ce280be7 100644 --- a/Lib/email/errors.py +++ b/Lib/email/errors.py @@ -105,3 +105,6 @@ class NonASCIILocalPartDefect(HeaderDefect): """local_part contains non-ASCII characters""" # This defect only occurs during unicode parsing, not when # parsing messages decoded from binary. + +class InvalidDateDefect(HeaderDefect): + """Header has unparseable or invalid date""" diff --git a/Lib/email/headerregistry.py b/Lib/email/headerregistry.py index 81fee146dcc357..47364560b91ae6 100644 --- a/Lib/email/headerregistry.py +++ b/Lib/email/headerregistry.py @@ -300,7 +300,14 @@ def parse(cls, value, kwds): kwds['parse_tree'] = parser.TokenList() return if isinstance(value, str): - value = utils.parsedate_to_datetime(value) + kwds['decoded'] = value + try: + value = utils.parsedate_to_datetime(value) + except (ValueError, TypeError): + kwds['defects'].append(errors.InvalidDateDefect('Invalid date value or format')) + kwds['datetime'] = None + kwds['parse_tree'] = parser.TokenList() + return kwds['datetime'] = value kwds['decoded'] = utils.format_datetime(kwds['datetime']) kwds['parse_tree'] = cls.value_parser(kwds['decoded']) diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py index af836dc9726622..975a734ba5bedb 100644 --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -203,6 +203,22 @@ def test_no_value_is_defect(self): self.assertEqual(len(h.defects), 1) self.assertIsInstance(h.defects[0], errors.HeaderMissingRequiredValue) + def test_invalid_date_format(self): + s = 'Not a date header' + h = self.make_header('date', s) + self.assertEqual(h, s) + self.assertIsNone(h.datetime) + self.assertEqual(len(h.defects), 1) + self.assertIsInstance(h.defects[0], errors.InvalidDateDefect) + + def test_invalid_date_value(self): + s = 'Tue, 06 Jun 2017 27:39:33 +0600' + h = self.make_header('date', s) + self.assertEqual(h, s) + self.assertIsNone(h.datetime) + self.assertEqual(len(h.defects), 1) + self.assertIsInstance(h.defects[0], errors.InvalidDateDefect) + def test_datetime_read_only(self): h = self.make_header('date', self.datestring) with self.assertRaises(AttributeError): diff --git a/Lib/test/test_email/test_inversion.py b/Lib/test/test_email/test_inversion.py index 8e8d67641b8943..7bd7f2a72067ad 100644 --- a/Lib/test/test_email/test_inversion.py +++ b/Lib/test/test_email/test_inversion.py @@ -46,6 +46,14 @@ def msg_as_input(self, msg): foo """),), + 'header_with_invalid_date': (dedent(b"""\ + Date: Tue, 06 Jun 2017 27:39:33 +0600 + From: abc@xyz.com + Subject: timezones + + How do they work even? + """),), + } payload_params = { diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py index 6dcb3bbe7aab8c..60f175a05d5437 100644 --- a/Lib/test/test_email/test_utils.py +++ b/Lib/test/test_email/test_utils.py @@ -48,6 +48,22 @@ def test_parsedate_to_datetime_naive(self): utils.parsedate_to_datetime(self.datestring + ' -0000'), self.naive_dt) + def test_parsedate_to_datetime_with_invalid_raises_typeerror(self): + with self.assertRaises(TypeError): + utils.parsedate_to_datetime('') + with self.assertRaises(TypeError): + utils.parsedate_to_datetime('0') + with self.assertRaises(TypeError): + utils.parsedate_to_datetime('A Complete Waste of Time') + + def test_parsedate_to_datetime_with_invalid_raises_valueerror(self): + with self.assertRaises(ValueError): + utils.parsedate_to_datetime('Tue, 06 Jun 2017 27:39:33 +0600') + with self.assertRaises(ValueError): + utils.parsedate_to_datetime('Tue, 06 Jun 2017 07:39:33 +2600') + with self.assertRaises(ValueError): + utils.parsedate_to_datetime('Tue, 06 Jun 2017 27:39:33') + class LocaltimeTests(unittest.TestCase):
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: