summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2015-01-21 20:59:40 +0100
committerClaude Paroz <claude@2xlibre.net>2015-01-23 08:58:34 +0100
commitb1bf8d64fbadcab860eb98662c49b8db33db0c3c (patch)
treeab937dc2d28b61365152c1cc61492bd79403854e /django
parent7b677fe063910e67dbeb123fcd164305e0425f34 (diff)
[1.7.x] Fixed #24193 -- Prevented unclosed file warnings in static.serve()
This regression was caused by 818e59a3f0. The patch is a partial backport of the new FileResponse class available in later Django versions. Thanks Raphaƫl Hertzog for the report, and Tim Graham and Collin Anderson for the reviews.
Diffstat (limited to 'django')
-rw-r--r--django/http/__init__.py5
-rw-r--r--django/http/response.py18
-rw-r--r--django/views/static.py8
3 files changed, 23 insertions, 8 deletions
diff --git a/django/http/__init__.py b/django/http/__init__.py
index fc5bd180ad..99a5233b07 100644
--- a/django/http/__init__.py
+++ b/django/http/__init__.py
@@ -1,7 +1,8 @@
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,
@@ -16,5 +17,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 b3f44cdf92..06126eda67 100644
--- a/django/http/response.py
+++ b/django/http/response.py
@@ -382,6 +382,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'):
@@ -391,6 +394,21 @@ class StreamingHttpResponse(HttpResponseBase):
return 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._iterator = iter(lambda: value.read(self.block_size), b'')
+ if hasattr(value, 'close'):
+ self._closable_objects.append(value)
+ else:
+ 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 0ce00a9963..19f57b72c1 100644
--- a/django/views/static.py
+++ b/django/views/static.py
@@ -11,14 +11,12 @@ 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
from django.utils.translation import ugettext as _, ugettext_lazy
-STREAM_CHUNK_SIZE = 4096
-
def serve(request, path, document_root=None, show_indexes=False):
"""
@@ -63,9 +61,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'
- f = open(fullpath, 'rb')
- response = StreamingHttpResponse(iter(lambda: f.read(STREAM_CHUNK_SIZE), b''),
- 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