diff --git a/falcon/request.py b/falcon/request.py index f41cc7e..3d3d164 100644 --- a/falcon/request.py +++ b/falcon/request.py @@ -187,8 +187,26 @@ class Request(object): @property def date(self): - """Value of the Date header, or None if missing.""" - return self._get_header_by_wsgi_name('DATE') + """Value of the Date header, converted to a datetime instance. + + Returns: + An instance of datetime.datetime representing the value of + the Date header, or None if the Date header is not present + in the request. + + Raises: + HTTPBadRequest: The date value could not be parsed, likely + because it does not confrom to RFC 1123. + + """ + + http_date = self._get_header_by_wsgi_name('DATE') + try: + return util.http_date_to_dt(http_date) + except ValueError: + msg = ('The value of the Date header could not be parsed. It ' + 'must be formatted according to RFC 1123.') + raise InvalidHeaderValueError(msg) @property def expect(self): diff --git a/falcon/util.py b/falcon/util.py index 68b5af2..001f6aa 100644 --- a/falcon/util.py +++ b/falcon/util.py @@ -16,6 +16,8 @@ limitations under the License. """ +import datetime + def dt_to_http(dt): """Converts a datetime instance to an HTTP date string. @@ -33,6 +35,11 @@ def dt_to_http(dt): return dt.strftime('%a, %d %b %Y %H:%M:%S GMT') +def http_date_to_dt(http_date): + return datetime.datetime.strptime( + http_date, '%a, %d %b %Y %H:%M:%S %Z') + + def to_query_str(params): """Converts a dict of params to an actual query string. diff --git a/tests/test_req_vars.py b/tests/test_req_vars.py index ac832cb..6244a34 100644 --- a/tests/test_req_vars.py +++ b/tests/test_req_vars.py @@ -1,3 +1,5 @@ +import datetime + import falcon from falcon.request import Request import falcon.testing as testing @@ -199,6 +201,17 @@ class TestReqVars(testing.TestBase): req = Request(testing.create_environ(headers=headers)) self.assertRaises(falcon.HTTPBadRequest, lambda: req.content_length) + def test_date(self): + date = datetime.datetime(2013, 4, 4, 5, 19, 18) + headers = {'date': 'Thu, 04 Apr 2013 05:19:18 GMT'} + req = Request(testing.create_environ(headers=headers)) + self.assertEquals(req.date, date) + + def test_date_invalid(self): + headers = {'date': 'Thu, 04 Apr 2013'} + req = Request(testing.create_environ(headers=headers)) + self.assertRaises(falcon.HTTPBadRequest, lambda: req.date) + def test_attribute_headers(self): date = testing.httpnow() hash = 'fa0d1a60ef6616bb28038515c8ea4cb2' @@ -212,7 +225,6 @@ class TestReqVars(testing.TestBase): self._test_attribute_header('Content-Type', 'text/plain', 'content_type') self._test_attribute_header('Expect', '100-continue', 'expect') - self._test_attribute_header('Date', date, 'date') self._test_attribute_header('If-Match', hash, 'if_match') self._test_attribute_header('If-Modified-Since', date, diff --git a/tests/test_utils.py b/tests/test_utils.py index 5eae1cd..16c4784 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -15,6 +15,15 @@ class TestFalconUtils(testtools.TestCase): falcon.dt_to_http(datetime(2013, 4, 4, 10, 28, 54)), 'Thu, 04 Apr 2013 10:28:54 GMT') + def test_http_date_to_dt(self): + self.assertEquals( + falcon.http_date_to_dt('Thu, 04 Apr 2013 00:00:00 GMT'), + datetime(2013, 4, 4)) + + self.assertEquals( + falcon.http_date_to_dt('Thu, 04 Apr 2013 10:28:54 GMT'), + datetime(2013, 4, 4, 10, 28, 54)) + def test_pack_query_params_none(self): self.assertEquals( falcon.to_query_str({}),