From 79956d06946c881cb71958f27a12f62b9cab8de5 Mon Sep 17 00:00:00 2001 From: Mark Lavin Date: Mon, 14 Apr 2014 19:44:05 -0400 Subject: [PATCH] Fixed #22440 -- Updated ConditionalGetMiddleware to comply with RFC 2616. --- django/middleware/http.py | 9 +++++++-- tests/middleware/tests.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/django/middleware/http.py b/django/middleware/http.py index 8e4bc55881..60fb194704 100644 --- a/django/middleware/http.py +++ b/django/middleware/http.py @@ -14,7 +14,10 @@ class ConditionalGetMiddleware(object): if not response.streaming and not response.has_header('Content-Length'): response['Content-Length'] = str(len(response.content)) - if response.has_header('ETag'): + # If-None-Match must be ignored if original result would be anything + # other than a 2XX or 304 status. 304 status would result in no change. + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26 + if 200 <= response.status_code < 300 and response.has_header('ETag'): if_none_match = request.META.get('HTTP_IF_NONE_MATCH') if if_none_match == response['ETag']: # Setting the status is enough here. The response handling path @@ -22,7 +25,9 @@ class ConditionalGetMiddleware(object): # http.conditional_content_removal()). response.status_code = 304 - if response.has_header('Last-Modified'): + # If-Modified-Since must be ignored if the original result was not a 200. + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25 + if response.status_code == 200 and response.has_header('Last-Modified'): if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE') if if_modified_since is not None: if_modified_since = parse_http_date_safe(if_modified_since) diff --git a/tests/middleware/tests.py b/tests/middleware/tests.py index 7df1d04418..556e07f72c 100644 --- a/tests/middleware/tests.py +++ b/tests/middleware/tests.py @@ -366,6 +366,19 @@ class ConditionalGetMiddlewareTest(TestCase): self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp) self.assertEqual(self.resp.status_code, 200) + def test_if_none_match_and_redirect(self): + self.req.META['HTTP_IF_NONE_MATCH'] = self.resp['ETag'] = 'spam' + self.resp['Location'] = '/' + self.resp.status_code = 301 + self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp) + self.assertEqual(self.resp.status_code, 301) + + def test_if_none_match_and_client_error(self): + self.req.META['HTTP_IF_NONE_MATCH'] = self.resp['ETag'] = 'spam' + self.resp.status_code = 400 + self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp) + self.assertEqual(self.resp.status_code, 400) + @override_settings(USE_ETAGS=True) def test_etag(self): req = HttpRequest() @@ -419,6 +432,21 @@ class ConditionalGetMiddlewareTest(TestCase): self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp) self.assertEqual(self.resp.status_code, 200) + def test_if_modified_since_and_redirect(self): + self.req.META['HTTP_IF_MODIFIED_SINCE'] = 'Sat, 12 Feb 2011 17:38:44 GMT' + self.resp['Last-Modified'] = 'Sat, 12 Feb 2011 17:35:44 GMT' + self.resp['Location'] = '/' + self.resp.status_code = 301 + self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp) + self.assertEqual(self.resp.status_code, 301) + + def test_if_modified_since_and_client_error(self): + self.req.META['HTTP_IF_MODIFIED_SINCE'] = 'Sat, 12 Feb 2011 17:38:44 GMT' + self.resp['Last-Modified'] = 'Sat, 12 Feb 2011 17:35:44 GMT' + self.resp.status_code = 400 + self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp) + self.assertEqual(self.resp.status_code, 400) + class XFrameOptionsMiddlewareTest(TestCase): """