浏览代码

Fixed #5897 -- Added the Content-Length response header in CommonMiddleware

Thanks Tim Graham for the review.
Claude Paroz 8 年之前
父节点
当前提交
9588718cd4

+ 4 - 0
django/middleware/common.py

@@ -123,6 +123,10 @@ class CommonMiddleware(MiddlewareMixin):
                     etag=unquote_etag(response['ETag']),
                     response=response,
                 )
+        # Add the Content-Length header to non-streaming responses if not
+        # already set.
+        if not response.streaming and not response.has_header('Content-Length'):
+            response['Content-Length'] = str(len(response.content))
 
         return response
 

+ 6 - 0
docs/ref/middleware.txt

@@ -66,6 +66,12 @@ Adds a few conveniences for perfectionists:
   for each request by MD5-hashing the page content, and it'll take care of
   sending ``Not Modified`` responses, if appropriate.
 
+* Sets the ``Content-Length`` header for non-streaming responses.
+
+.. versionchanged: 1.11
+
+    Older versions didn't set the ``Content-Length`` header.
+
 .. attribute:: CommonMiddleware.response_redirect_class
 
 Defaults to :class:`~django.http.HttpResponsePermanentRedirect`. Subclass

+ 3 - 0
docs/releases/1.11.txt

@@ -197,6 +197,9 @@ Requests and Responses
 
 * Added :meth:`QueryDict.fromkeys() <django.http.QueryDict.fromkeys>`.
 
+* :class:`~django.middleware.common.CommonMiddleware` now sets the
+  ``Content-Length`` response header for non-streaming responses.
+
 Serialization
 ~~~~~~~~~~~~~
 

+ 24 - 0
tests/middleware/tests.py

@@ -285,6 +285,27 @@ class CommonMiddlewareTest(SimpleTestCase):
         second_res = CommonMiddleware().process_response(second_req, HttpResponse('content'))
         self.assertEqual(second_res.status_code, 304)
 
+    # Tests for the Content-Length header
+
+    def test_content_length_header_added(self):
+        response = HttpResponse('content')
+        self.assertNotIn('Content-Length', response)
+        response = CommonMiddleware().process_response(HttpRequest(), response)
+        self.assertEqual(int(response['Content-Length']), len(response.content))
+
+    def test_content_length_header_not_added_for_streaming_response(self):
+        response = StreamingHttpResponse('content')
+        self.assertNotIn('Content-Length', response)
+        response = CommonMiddleware().process_response(HttpRequest(), response)
+        self.assertNotIn('Content-Length', response)
+
+    def test_content_length_header_not_changed(self):
+        response = HttpResponse()
+        bad_content_length = len(response.content) + 10
+        response['Content-Length'] = bad_content_length
+        response = CommonMiddleware().process_response(HttpRequest(), response)
+        self.assertEqual(int(response['Content-Length']), bad_content_length)
+
     # Other tests
 
     @override_settings(DISALLOWED_USER_AGENTS=[re.compile(r'foo')])
@@ -445,6 +466,9 @@ class ConditionalGetMiddlewareTest(SimpleTestCase):
 
     def test_content_length_header_added(self):
         content_length = len(self.resp.content)
+        # Already set by CommonMiddleware, remove it to check that
+        # ConditionalGetMiddleware readds it.
+        del self.resp['Content-Length']
         self.assertNotIn('Content-Length', self.resp)
         self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
         self.assertIn('Content-Length', self.resp)

+ 1 - 0
tests/project_template/test_settings.py

@@ -41,6 +41,7 @@ class TestStartProjectSettings(TestCase):
             response = self.client.get('/empty/')
             headers = sorted(response.serialize_headers().split(b'\r\n'))
             self.assertEqual(headers, [
+                b'Content-Length: 0',
                 b'Content-Type: text/html; charset=utf-8',
                 b'X-Frame-Options: SAMEORIGIN',
             ])

+ 6 - 5
tests/wsgi/tests.py

@@ -41,11 +41,12 @@ class WSGITest(SimpleTestCase):
 
         self.assertEqual(response_data["status"], "200 OK")
         self.assertEqual(
-            response_data["headers"],
-            [('Content-Type', 'text/html; charset=utf-8')])
-        self.assertEqual(
-            bytes(response),
-            b"Content-Type: text/html; charset=utf-8\r\n\r\nHello World!")
+            set(response_data["headers"]),
+            {('Content-Length', '12'), ('Content-Type', 'text/html; charset=utf-8')})
+        self.assertTrue(bytes(response) in [
+            b"Content-Length: 12\r\nContent-Type: text/html; charset=utf-8\r\n\r\nHello World!",
+            b"Content-Type: text/html; charset=utf-8\r\nContent-Length: 12\r\n\r\nHello World!"
+        ])
 
     def test_file_wrapper(self):
         """