diff --git a/falcon/request.py b/falcon/request.py index cdb287e..f1d4b7e 100644 --- a/falcon/request.py +++ b/falcon/request.py @@ -622,12 +622,13 @@ class Request(object): try: http_date = self.get_header(header, required=required) - return util.http_date_to_dt(http_date) + return util.http_date_to_dt(http_date, obs_date=True) except TypeError: # When the header does not exist and isn't required return None except ValueError: - msg = ('It must be formatted according to RFC 1123.') + msg = ('It must be formatted according to RFC 7231, ' + 'Section 7.1.1.1') raise HTTPInvalidHeader(msg, header) def get_param(self, name, required=False, store=None, default=None): diff --git a/falcon/util/misc.py b/falcon/util/misc.py index 827ecf3..84f1068 100644 --- a/falcon/util/misc.py +++ b/falcon/util/misc.py @@ -101,19 +101,41 @@ def dt_to_http(dt): return dt.strftime('%a, %d %b %Y %H:%M:%S GMT') -def http_date_to_dt(http_date): +def http_date_to_dt(http_date, obs_date=False): """Converts an HTTP date string to a datetime instance. Args: http_date (str): An RFC 1123 date string, e.g.: "Tue, 15 Nov 1994 12:45:26 GMT". + obs_date (bool): Support obs-date formats according to RFC 7231, e.g.: + "Sunday, 06-Nov-94 08:49:37 GMT" + "Sun Nov 6 08:49:37 1994". Returns: datetime: A UTC datetime instance corresponding to the given HTTP date. + + Raises: + ValueError: http_date doesn't match any of the available time formats """ - return strptime(http_date, '%a, %d %b %Y %H:%M:%S %Z') + time_formats = ['%a, %d %b %Y %H:%M:%S %Z'] + + if obs_date: + time_formats.extend([ + '%A, %d-%b-%y %H:%M:%S %Z', + '%a %b %d %H:%M:%S %Y', + ]) + + # Loop through the formats and return the first that matches + for time_format in time_formats: + try: + return strptime(http_date, time_format) + except ValueError: + continue + + # Did not match any formats + raise ValueError('time data %r does not match known formats' % http_date) def to_query_str(params): diff --git a/tests/test_req_vars.py b/tests/test_req_vars.py index 56a786d..48dfe06 100644 --- a/tests/test_req_vars.py +++ b/tests/test_req_vars.py @@ -527,7 +527,7 @@ class TestReqVars(testing.TestBase): headers = {header: 'Thu, 04 Apr 2013'} expected_desc = ('The value provided for the {0} ' 'header is invalid. It must be formatted ' - 'according to RFC 1123.') + 'according to RFC 7231, Section 7.1.1.1') self._test_error_details(headers, attr, falcon.HTTPInvalidHeader, diff --git a/tests/test_utils.py b/tests/test_utils.py index 0745841..5649175 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -79,6 +79,15 @@ class TestFalconUtils(testtools.TestCase): falcon.http_date_to_dt('Thu, 04 Apr 2013 10:28:54 GMT'), datetime(2013, 4, 4, 10, 28, 54)) + self.assertEqual( + falcon.http_date_to_dt('Sunday, 06-Nov-94 08:49:37 GMT', + obs_date=True), + datetime(1994, 11, 6, 8, 49, 37)) + + self.assertEqual( + falcon.http_date_to_dt('Sun Nov 6 08:49:37 1994', obs_date=True), + datetime(1994, 11, 6, 8, 49, 37)) + def test_pack_query_params_none(self): self.assertEqual( falcon.to_query_str({}),