From 7cfe8e8fce7677ec696f42a7d1501a97e8191a3d Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Wed, 22 Aug 2012 18:06:03 +0200 Subject: [PATCH] Fixed #11340 -- Prevented HttpResponseNotModified to have content/content-type The HTTP 1.1 spec tells that the 304 response MUST NOT contain a message body. Thanks aparajita for the report. --- django/http/__init__.py | 10 ++++++++++ django/views/static.py | 2 +- docs/ref/request-response.txt | 5 +++-- tests/regressiontests/httpwrappers/tests.py | 12 +++++++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/django/http/__init__.py b/django/http/__init__.py index 701e76f7fa..7782ebe648 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -744,6 +744,16 @@ class HttpResponsePermanentRedirect(HttpResponseRedirectBase): class HttpResponseNotModified(HttpResponse): status_code = 304 + def __init__(self, *args, **kwargs): + super(HttpResponseNotModified, self).__init__(*args, **kwargs) + del self['content-type'] + + @HttpResponse.content.setter + def content(self, value): + if value: + raise AttributeError("You cannot set content to a 304 (Not Modified) response") + self._container = [] + class HttpResponseBadRequest(HttpResponse): status_code = 400 diff --git a/django/views/static.py b/django/views/static.py index bcac9475e2..2ff22ce13f 100644 --- a/django/views/static.py +++ b/django/views/static.py @@ -61,7 +61,7 @@ def serve(request, path, document_root=None, show_indexes=False): mimetype = mimetype or 'application/octet-stream' if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'), statobj.st_mtime, statobj.st_size): - return HttpResponseNotModified(content_type=mimetype) + return HttpResponseNotModified() with open(fullpath, 'rb') as f: response = HttpResponse(f.read(), content_type=mimetype) response["Last-Modified"] = http_date(statobj.st_mtime) diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index 551ee00c6b..8d514dc533 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -743,8 +743,9 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in .. class:: HttpResponseNotModified - The constructor doesn't take any arguments. Use this to designate that a - page hasn't been modified since the user's last request (status code 304). + The constructor doesn't take any arguments and no content should be added + to this response. Use this to designate that a page hasn't been modified + since the user's last request (status code 304). .. class:: HttpResponseBadRequest diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py index bbb2518b32..c84b2cd44e 100644 --- a/tests/regressiontests/httpwrappers/tests.py +++ b/tests/regressiontests/httpwrappers/tests.py @@ -6,7 +6,7 @@ import pickle from django.core.exceptions import SuspiciousOperation from django.http import (QueryDict, HttpResponse, HttpResponseRedirect, - HttpResponsePermanentRedirect, + HttpResponsePermanentRedirect, HttpResponseNotModified, SimpleCookie, BadHeaderError, parse_cookie) from django.utils import six @@ -330,6 +330,16 @@ class HttpResponseTests(unittest.TestCase): HttpResponsePermanentRedirect, url) +class HttpResponseSubclassesTests(unittest.TestCase): + def test_not_modified(self): + response = HttpResponseNotModified() + self.assertEqual(response.status_code, 304) + # 304 responses should not have content/content-type + with self.assertRaises(AttributeError): + response.content = "Hello dear" + self.assertNotIn('content-type', response) + + class CookieTests(unittest.TestCase): def test_encode(self): """