mirror of
https://github.com/django/django.git
synced 2024-11-29 22:56:46 +01:00
Removed compatibility code for streaming responses.
This code provided a deprecation path for old-style streaming responses. Refs #6527, #7581.
This commit is contained in:
parent
59b0c48ce2
commit
8b9b8d3bda
@ -2,9 +2,9 @@ from django.http.cookie import SimpleCookie, parse_cookie
|
||||
from django.http.request import (HttpRequest, QueryDict, UnreadablePostError,
|
||||
build_request_repr)
|
||||
from django.http.response import (HttpResponse, StreamingHttpResponse,
|
||||
CompatibleStreamingHttpResponse, HttpResponsePermanentRedirect,
|
||||
HttpResponseRedirect, HttpResponseNotModified, HttpResponseBadRequest,
|
||||
HttpResponseForbidden, HttpResponseNotFound, HttpResponseNotAllowed,
|
||||
HttpResponseGone, HttpResponseServerError, Http404, BadHeaderError)
|
||||
HttpResponseRedirect, HttpResponsePermanentRedirect,
|
||||
HttpResponseNotModified, HttpResponseBadRequest, HttpResponseForbidden,
|
||||
HttpResponseNotFound, HttpResponseNotAllowed, HttpResponseGone,
|
||||
HttpResponseServerError, Http404, BadHeaderError)
|
||||
from django.http.utils import (fix_location_header, conditional_content_removal,
|
||||
fix_IE_for_attach, fix_IE_for_vary)
|
||||
|
@ -2,7 +2,6 @@ from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import datetime
|
||||
import time
|
||||
import warnings
|
||||
from email.header import Header
|
||||
try:
|
||||
from urllib.parse import urlparse
|
||||
@ -332,53 +331,27 @@ class HttpResponse(HttpResponseBase):
|
||||
else:
|
||||
__str__ = serialize
|
||||
|
||||
def _consume_content(self):
|
||||
# If the response was instantiated with an iterator, when its content
|
||||
# is accessed, the iterator is going be exhausted and the content
|
||||
# loaded in memory. At this point, it's better to abandon the original
|
||||
# iterator and save the content for later reuse. This is a temporary
|
||||
# solution. See the comment in __iter__ below for the long term plan.
|
||||
if self._base_content_is_iter:
|
||||
self.content = b''.join(self.make_bytes(e) for e in self._container)
|
||||
|
||||
@property
|
||||
def content(self):
|
||||
self._consume_content()
|
||||
return b''.join(self.make_bytes(e) for e in self._container)
|
||||
|
||||
@content.setter
|
||||
def content(self, value):
|
||||
if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)):
|
||||
self._container = value
|
||||
self._base_content_is_iter = True
|
||||
if hasattr(value, 'close'):
|
||||
self._closable_objects.append(value)
|
||||
else:
|
||||
self._container = [value]
|
||||
self._base_content_is_iter = False
|
||||
value = b''.join(self.make_bytes(e) for e in value)
|
||||
self._container = [value]
|
||||
|
||||
def __iter__(self):
|
||||
# Raise a deprecation warning only if the content wasn't consumed yet,
|
||||
# because the response may be intended to be streamed.
|
||||
# Once the deprecation completes, iterators should be consumed upon
|
||||
# assignment rather than upon access. The _consume_content method
|
||||
# should be removed. See #6527.
|
||||
if self._base_content_is_iter:
|
||||
warnings.warn(
|
||||
'Creating streaming responses with `HttpResponse` is '
|
||||
'deprecated. Use `StreamingHttpResponse` instead '
|
||||
'if you need the streaming behavior.',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
if not hasattr(self, '_iterator'):
|
||||
self._iterator = iter(self._container)
|
||||
return self
|
||||
|
||||
def write(self, content):
|
||||
self._consume_content()
|
||||
self._container.append(content)
|
||||
|
||||
def tell(self):
|
||||
self._consume_content()
|
||||
return len(self.content)
|
||||
|
||||
|
||||
@ -416,35 +389,6 @@ class StreamingHttpResponse(HttpResponseBase):
|
||||
self._closable_objects.append(value)
|
||||
|
||||
|
||||
class CompatibleStreamingHttpResponse(StreamingHttpResponse):
|
||||
"""
|
||||
This class maintains compatibility with middleware that doesn't know how
|
||||
to handle the content of a streaming response by exposing a `content`
|
||||
attribute that will consume and cache the content iterator when accessed.
|
||||
|
||||
These responses will stream only if no middleware attempts to access the
|
||||
`content` attribute. Otherwise, they will behave like a regular response,
|
||||
and raise a `DeprecationWarning`.
|
||||
"""
|
||||
@property
|
||||
def content(self):
|
||||
warnings.warn(
|
||||
'Accessing the `content` attribute on a streaming response is '
|
||||
'deprecated. Use the `streaming_content` attribute instead.',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
content = b''.join(self)
|
||||
self.streaming_content = [content]
|
||||
return content
|
||||
|
||||
@content.setter
|
||||
def content(self, content):
|
||||
warnings.warn(
|
||||
'Accessing the `content` attribute on a streaming response is '
|
||||
'deprecated. Use the `streaming_content` attribute instead.',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
self.streaming_content = [content]
|
||||
|
||||
|
||||
class HttpResponseRedirectBase(HttpResponse):
|
||||
allowed_schemes = ['http', 'https', 'ftp']
|
||||
|
||||
@ -478,7 +422,6 @@ class HttpResponseNotModified(HttpResponse):
|
||||
if value:
|
||||
raise AttributeError("You cannot set content to a 304 (Not Modified) response")
|
||||
self._container = []
|
||||
self._base_content_is_iter = False
|
||||
|
||||
|
||||
class HttpResponseBadRequest(HttpResponse):
|
||||
|
@ -14,8 +14,8 @@ try:
|
||||
except ImportError: # Python 2
|
||||
from urllib import unquote
|
||||
|
||||
from django.http import (CompatibleStreamingHttpResponse, Http404,
|
||||
HttpResponse, HttpResponseRedirect, HttpResponseNotModified)
|
||||
from django.http import (Http404, HttpResponse, HttpResponseRedirect,
|
||||
HttpResponseNotModified, StreamingHttpResponse)
|
||||
from django.template import loader, Template, Context, TemplateDoesNotExist
|
||||
from django.utils.http import http_date, parse_http_date
|
||||
from django.utils.translation import ugettext as _, ugettext_noop
|
||||
@ -63,8 +63,8 @@ def serve(request, path, document_root=None, show_indexes=False):
|
||||
return HttpResponseNotModified()
|
||||
content_type, encoding = mimetypes.guess_type(fullpath)
|
||||
content_type = content_type or 'application/octet-stream'
|
||||
response = CompatibleStreamingHttpResponse(open(fullpath, 'rb'),
|
||||
content_type=content_type)
|
||||
response = StreamingHttpResponse(open(fullpath, 'rb'),
|
||||
content_type=content_type)
|
||||
response["Last-Modified"] = http_date(statobj.st_mtime)
|
||||
if stat.S_ISREG(statobj.st_mode):
|
||||
response["Content-Length"] = statobj.st_size
|
||||
|
@ -324,19 +324,10 @@ class HttpResponseTests(unittest.TestCase):
|
||||
r.content = [1, 2, 3]
|
||||
self.assertEqual(r.content, b'123')
|
||||
|
||||
#test retrieval explicitly using iter (deprecated) and odd inputs
|
||||
#test odd inputs
|
||||
r = HttpResponse()
|
||||
r.content = ['1', '2', 3, '\u079e']
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always", DeprecationWarning)
|
||||
my_iter = iter(r)
|
||||
self.assertEqual(w[0].category, DeprecationWarning)
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always", DeprecationWarning)
|
||||
result = list(my_iter)
|
||||
self.assertEqual(w[0].category, DeprecationWarning)
|
||||
#'\xde\x9e' == unichr(1950).encode('utf-8')
|
||||
self.assertEqual(result, [b'1', b'2', b'3', b'\xde\x9e'])
|
||||
self.assertEqual(r.content, b'123\xde\x9e')
|
||||
|
||||
#with Content-Encoding header
|
||||
@ -344,9 +335,8 @@ class HttpResponseTests(unittest.TestCase):
|
||||
r['Content-Encoding'] = 'winning'
|
||||
r.content = [b'abc', b'def']
|
||||
self.assertEqual(r.content, b'abcdef')
|
||||
r.content = ['\u079e']
|
||||
self.assertRaises(TypeError if six.PY3 else UnicodeEncodeError,
|
||||
getattr, r, 'content')
|
||||
setattr, r, 'content', ['\u079e'])
|
||||
|
||||
# .content can safely be accessed multiple times.
|
||||
r = HttpResponse(iter(['hello', 'world']))
|
||||
@ -358,15 +348,12 @@ class HttpResponseTests(unittest.TestCase):
|
||||
# accessing .content still works
|
||||
self.assertEqual(r.content, b'helloworld')
|
||||
|
||||
# XXX accessing .content doesn't work if the response was iterated first
|
||||
# XXX change this when the deprecation completes in HttpResponse
|
||||
# Accessing .content also works if the response was iterated first.
|
||||
r = HttpResponse(iter(['hello', 'world']))
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
self.assertEqual(b''.join(r), b'helloworld')
|
||||
self.assertEqual(r.content, b'') # not the expected result!
|
||||
self.assertEqual(b''.join(r), b'helloworld')
|
||||
self.assertEqual(r.content, b'helloworld')
|
||||
|
||||
# additional content can be written to the response.
|
||||
# Additional content can be written to the response.
|
||||
r = HttpResponse(iter(['hello', 'world']))
|
||||
self.assertEqual(r.content, b'helloworld')
|
||||
r.write('!')
|
||||
|
Loading…
Reference in New Issue
Block a user