diff --git a/django/middleware/http.py b/django/middleware/http.py index a075ccfe79..41389d930e 100644 --- a/django/middleware/http.py +++ b/django/middleware/http.py @@ -18,6 +18,12 @@ class ConditionalGetMiddleware(MiddlewareMixin): if not response.streaming and not response.has_header('Content-Length'): response['Content-Length'] = str(len(response.content)) + # It's too late to prevent an unsafe request with a 412 response, and + # for a HEAD request, the response body is always empty so computing + # an accurate ETag isn't possible. + if request.method != 'GET': + return response + if self.needs_etag(response) and not response.has_header('ETag'): set_response_etag(response) diff --git a/tests/middleware/tests.py b/tests/middleware/tests.py index 7adf4b3a77..680354e956 100644 --- a/tests/middleware/tests.py +++ b/tests/middleware/tests.py @@ -629,6 +629,31 @@ class ConditionalGetMiddlewareTest(SimpleTestCase): self.assertEqual(new_response.cookies, self.resp.cookies) self.assertNotIn('Content-Language', new_response) + def test_no_unsafe(self): + """ + ConditionalGetMiddleware shouldn't return a conditional response on an + unsafe request. A response has already been generated by the time + ConditionalGetMiddleware is called, so it's too late to return a 412 + Precondition Failed. + """ + get_response = ConditionalGetMiddleware().process_response(self.req, self.resp) + etag = get_response['ETag'] + put_request = RequestFactory().put('/', HTTP_IF_MATCH=etag) + put_response = HttpResponse(status=200) + conditional_get_response = ConditionalGetMiddleware().process_response(put_request, put_response) + self.assertEqual(conditional_get_response.status_code, 200) # should never be a 412 + + def test_no_head(self): + """ + ConditionalGetMiddleware shouldn't compute and return an ETag on a + HEAD request since it can't do so accurately without access to the + response body of the corresponding GET. + """ + request = RequestFactory().head('/') + response = HttpResponse(status=200) + conditional_get_response = ConditionalGetMiddleware().process_response(request, response) + self.assertNotIn('ETag', conditional_get_response) + class XFrameOptionsMiddlewareTest(SimpleTestCase): """