summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorCollin Anderson <cmawebsite@gmail.com>2015-01-03 12:06:24 -0500
committerTim Graham <timograham@gmail.com>2015-01-05 10:51:52 -0500
commit3d2cae0896ee8026d1c2c5d31e4c4c8f74f2fef4 (patch)
tree1abf00da86cd8831b829124a32058ea589b78b3c /django
parent05f702b94ca4ad77236a1e299270e8014def02e6 (diff)
Fixed #24072 -- Added FileResponse for streaming binary files.
Diffstat (limited to 'django')
-rw-r--r--django/core/handlers/wsgi.py2
-rw-r--r--django/http/__init__.py8
-rw-r--r--django/http/response.py19
-rw-r--r--django/views/static.py5
4 files changed, 28 insertions, 6 deletions
diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py
index b947177bd1..b4402686c0 100644
--- a/django/core/handlers/wsgi.py
+++ b/django/core/handlers/wsgi.py
@@ -197,6 +197,8 @@ class WSGIHandler(base.BaseHandler):
for c in response.cookies.values():
response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
start_response(force_str(status), response_headers)
+ if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
+ response = environ['wsgi.file_wrapper'](response.file_to_stream)
return response
diff --git a/django/http/__init__.py b/django/http/__init__.py
index fc5bd180ad..cf1e5d3950 100644
--- a/django/http/__init__.py
+++ b/django/http/__init__.py
@@ -1,11 +1,13 @@
from django.http.cookie import SimpleCookie, parse_cookie
from django.http.request import (HttpRequest, QueryDict,
RawPostDataException, UnreadablePostError, build_request_repr)
-from django.http.response import (HttpResponse, StreamingHttpResponse,
+from django.http.response import (
+ HttpResponse, StreamingHttpResponse, FileResponse,
HttpResponseRedirect, HttpResponsePermanentRedirect,
HttpResponseNotModified, HttpResponseBadRequest, HttpResponseForbidden,
HttpResponseNotFound, HttpResponseNotAllowed, HttpResponseGone,
- HttpResponseServerError, Http404, BadHeaderError, JsonResponse)
+ HttpResponseServerError, Http404, BadHeaderError, JsonResponse,
+)
from django.http.utils import fix_location_header, conditional_content_removal
__all__ = [
@@ -16,5 +18,5 @@ __all__ = [
'HttpResponseBadRequest', 'HttpResponseForbidden', 'HttpResponseNotFound',
'HttpResponseNotAllowed', 'HttpResponseGone', 'HttpResponseServerError',
'Http404', 'BadHeaderError', 'fix_location_header', 'JsonResponse',
- 'conditional_content_removal',
+ 'FileResponse', 'conditional_content_removal',
]
diff --git a/django/http/response.py b/django/http/response.py
index 2735e3c59d..5168834b23 100644
--- a/django/http/response.py
+++ b/django/http/response.py
@@ -417,6 +417,9 @@ class StreamingHttpResponse(HttpResponseBase):
@streaming_content.setter
def streaming_content(self, value):
+ self._set_streaming_content(value)
+
+ def _set_streaming_content(self, value):
# Ensure we can never iterate on "value" more than once.
self._iterator = iter(value)
if hasattr(value, 'close'):
@@ -429,6 +432,22 @@ class StreamingHttpResponse(HttpResponseBase):
return b''.join(self.streaming_content)
+class FileResponse(StreamingHttpResponse):
+ """
+ A streaming HTTP response class optimized for files.
+ """
+ block_size = 4096
+
+ def _set_streaming_content(self, value):
+ if hasattr(value, 'read'):
+ self.file_to_stream = value
+ filelike = value
+ value = iter(lambda: filelike.read(self.block_size), b'')
+ else:
+ self.file_to_stream = None
+ super(FileResponse, self)._set_streaming_content(value)
+
+
class HttpResponseRedirectBase(HttpResponse):
allowed_schemes = ['http', 'https', 'ftp']
diff --git a/django/views/static.py b/django/views/static.py
index 2998688284..75e81eccd3 100644
--- a/django/views/static.py
+++ b/django/views/static.py
@@ -11,7 +11,7 @@ import posixpath
import re
from django.http import (Http404, HttpResponse, HttpResponseRedirect,
- HttpResponseNotModified, StreamingHttpResponse)
+ HttpResponseNotModified, FileResponse)
from django.template import loader, Template, Context, TemplateDoesNotExist
from django.utils.http import http_date, parse_http_date
from django.utils.six.moves.urllib.parse import unquote
@@ -63,8 +63,7 @@ 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 = StreamingHttpResponse(open(fullpath, 'rb'),
- content_type=content_type)
+ response = FileResponse(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