mirror of
				https://github.com/django/django.git
				synced 2025-10-30 11:37:19 +00:00 
			
		
		
		
	Fixed #5897 -- Added the Content-Length response header in CommonMiddleware
Thanks Tim Graham for the review.
This commit is contained in:
		
							parent
							
								
									ca77b50905
								
							
						
					
					
						commit
						9588718cd4
					
				
					 6 changed files with 44 additions and 5 deletions
				
			
		|  | @ -123,6 +123,10 @@ class CommonMiddleware(MiddlewareMixin): | ||||||
|                     etag=unquote_etag(response['ETag']), |                     etag=unquote_etag(response['ETag']), | ||||||
|                     response=response, |                     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 |         return response | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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 |   for each request by MD5-hashing the page content, and it'll take care of | ||||||
|   sending ``Not Modified`` responses, if appropriate. |   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 | .. attribute:: CommonMiddleware.response_redirect_class | ||||||
| 
 | 
 | ||||||
| Defaults to :class:`~django.http.HttpResponsePermanentRedirect`. Subclass | Defaults to :class:`~django.http.HttpResponsePermanentRedirect`. Subclass | ||||||
|  |  | ||||||
|  | @ -197,6 +197,9 @@ Requests and Responses | ||||||
| 
 | 
 | ||||||
| * Added :meth:`QueryDict.fromkeys() <django.http.QueryDict.fromkeys>`. | * 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 | Serialization | ||||||
| ~~~~~~~~~~~~~ | ~~~~~~~~~~~~~ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -285,6 +285,27 @@ class CommonMiddlewareTest(SimpleTestCase): | ||||||
|         second_res = CommonMiddleware().process_response(second_req, HttpResponse('content')) |         second_res = CommonMiddleware().process_response(second_req, HttpResponse('content')) | ||||||
|         self.assertEqual(second_res.status_code, 304) |         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 |     # Other tests | ||||||
| 
 | 
 | ||||||
|     @override_settings(DISALLOWED_USER_AGENTS=[re.compile(r'foo')]) |     @override_settings(DISALLOWED_USER_AGENTS=[re.compile(r'foo')]) | ||||||
|  | @ -445,6 +466,9 @@ class ConditionalGetMiddlewareTest(SimpleTestCase): | ||||||
| 
 | 
 | ||||||
|     def test_content_length_header_added(self): |     def test_content_length_header_added(self): | ||||||
|         content_length = len(self.resp.content) |         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.assertNotIn('Content-Length', self.resp) | ||||||
|         self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp) |         self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp) | ||||||
|         self.assertIn('Content-Length', self.resp) |         self.assertIn('Content-Length', self.resp) | ||||||
|  |  | ||||||
|  | @ -41,6 +41,7 @@ class TestStartProjectSettings(TestCase): | ||||||
|             response = self.client.get('/empty/') |             response = self.client.get('/empty/') | ||||||
|             headers = sorted(response.serialize_headers().split(b'\r\n')) |             headers = sorted(response.serialize_headers().split(b'\r\n')) | ||||||
|             self.assertEqual(headers, [ |             self.assertEqual(headers, [ | ||||||
|  |                 b'Content-Length: 0', | ||||||
|                 b'Content-Type: text/html; charset=utf-8', |                 b'Content-Type: text/html; charset=utf-8', | ||||||
|                 b'X-Frame-Options: SAMEORIGIN', |                 b'X-Frame-Options: SAMEORIGIN', | ||||||
|             ]) |             ]) | ||||||
|  |  | ||||||
|  | @ -41,11 +41,12 @@ class WSGITest(SimpleTestCase): | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(response_data["status"], "200 OK") |         self.assertEqual(response_data["status"], "200 OK") | ||||||
|         self.assertEqual( |         self.assertEqual( | ||||||
|             response_data["headers"], |             set(response_data["headers"]), | ||||||
|             [('Content-Type', 'text/html; charset=utf-8')]) |             {('Content-Length', '12'), ('Content-Type', 'text/html; charset=utf-8')}) | ||||||
|         self.assertEqual( |         self.assertTrue(bytes(response) in [ | ||||||
|             bytes(response), |             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\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): |     def test_file_wrapper(self): | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Claude Paroz
						Claude Paroz