Fixed #26052 -- Moved conditional_content_removal() processing to the test client.

This commit is contained in:
Tim Graham 2016-04-25 07:56:07 -04:00
parent bd145e7209
commit bb0b4b705b
6 changed files with 33 additions and 49 deletions

View File

@ -24,10 +24,6 @@ logger = logging.getLogger('django.request')
class BaseHandler(object):
# Changes that are always applied to a response (in this order).
response_fixes = [
http.conditional_content_removal,
]
def __init__(self):
self._request_middleware = None
@ -230,7 +226,6 @@ class BaseHandler(object):
"%s.process_response didn't return an "
"HttpResponse object. It returned None instead."
% (middleware_method.__self__.__class__.__name__))
response = self.apply_response_fixes(request, response)
except Exception: # Any exception should be gathered and handled
signals.got_request_exception.send(sender=self.__class__, request=request)
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
@ -289,13 +284,3 @@ class BaseHandler(object):
# Return an HttpResponse that displays a friendly error message.
callback, param_dict = resolver.resolve_error_handler(500)
return callback(request, **param_dict)
def apply_response_fixes(self, request, response):
"""
Applies each of the functions in self.response_fixes to the request and
response, modifying the response in the process. Returns the new
response.
"""
for func in self.response_fixes:
response = func(request, response)
return response

View File

@ -9,7 +9,6 @@ from django.http.response import (
HttpResponsePermanentRedirect, HttpResponseRedirect,
HttpResponseServerError, JsonResponse, StreamingHttpResponse,
)
from django.http.utils import conditional_content_removal
__all__ = [
'SimpleCookie', 'parse_cookie', 'HttpRequest', 'QueryDict',
@ -19,5 +18,4 @@ __all__ = [
'HttpResponseBadRequest', 'HttpResponseForbidden', 'HttpResponseNotFound',
'HttpResponseNotAllowed', 'HttpResponseGone', 'HttpResponseServerError',
'Http404', 'BadHeaderError', 'JsonResponse', 'FileResponse',
'conditional_content_removal',
]

View File

@ -1,28 +0,0 @@
"""
Functions that modify an HTTP request or response in some way.
"""
# This group of functions are run as part of the response handling, after
# everything else, including all response middleware. Think of them as
# "compulsory response middleware". Be careful about what goes here, because
# it's a little fiddly to override this behavior, so they should be truly
# universally applicable.
def conditional_content_removal(request, response):
"""
Removes the content of responses for HEAD requests, 1xx, 204 and 304
responses. Ensures compliance with RFC 2616, section 4.3.
"""
if 100 <= response.status_code < 200 or response.status_code in (204, 304):
if response.streaming:
response.streaming_content = []
else:
response.content = b''
response['Content-Length'] = '0'
if request.method == 'HEAD':
if response.streaming:
response.streaming_content = []
else:
response.content = b''
return response

View File

@ -92,6 +92,26 @@ def closing_iterator_wrapper(iterable, close):
request_finished.connect(close_old_connections)
def conditional_content_removal(request, response):
"""
Simulate the behavior of most Web servers by removing the content of
responses for HEAD requests, 1xx, 204, and 304 responses. Ensures
compliance with RFC 2616, section 4.3.
"""
if 100 <= response.status_code < 200 or response.status_code in (204, 304):
if response.streaming:
response.streaming_content = []
else:
response.content = b''
response['Content-Length'] = '0'
if request.method == 'HEAD':
if response.streaming:
response.streaming_content = []
else:
response.content = b''
return response
class ClientHandler(BaseHandler):
"""
A HTTP Handler that can be used for testing purposes. Uses the WSGI
@ -120,6 +140,10 @@ class ClientHandler(BaseHandler):
# Request goes through middleware.
response = self.get_response(request)
# Simulate behaviors of most Web servers.
conditional_content_removal(request, response)
# Attach the originating request to the response so that it could be
# later retrieved.
response.wsgi_request = request

View File

@ -778,6 +778,11 @@ Miscellaneous
attribute to ``False`` to disable it. You could also add the ``novalidate``
attribute to ``<form>`` if you don't want browser validation.
* The WSGI handler no longer removes content of responses from ``HEAD``
requests or responses with a ``status_code`` of 100-199, 204, or 304. Most
Web servers already implement this behavior. Responses retrieved using the
Django test client continue to have these "response fixes" applied.
.. _deprecated-features-1.10:
Features deprecated in 1.10

View File

@ -4,8 +4,8 @@ import gzip
import io
from django.http import HttpRequest, HttpResponse, StreamingHttpResponse
from django.http.utils import conditional_content_removal
from django.test import SimpleTestCase
from django.test.client import conditional_content_removal
# based on Python 3.3's gzip.compress
@ -19,12 +19,12 @@ def gzip_compress(data):
return buf.getvalue()
class HttpUtilTests(SimpleTestCase):
class ConditionalContentTests(SimpleTestCase):
def test_conditional_content_removal(self):
"""
Tests that content is removed from regular and streaming responses with
a status_code of 100-199, 204, 304 or a method of "HEAD".
Content is removed from regular and streaming responses with a
status_code of 100-199, 204, 304, or a method of "HEAD".
"""
req = HttpRequest()