mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-04-22 07:34:45 +00:00
Added streaming sendfile backend
The simple sendfile backend doesn't stream responses. This commit adds a backend that does.
This commit is contained in:
parent
b3348534cc
commit
f70eb09d07
2 changed files with 66 additions and 4 deletions
63
wagtail/utils/sendfile_streaming_backend.py
Normal file
63
wagtail/utils/sendfile_streaming_backend.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Sendfile "streaming" backend
|
||||
# This is based on sendfiles builtin "simple" backend but uses a StreamingHttpResponse
|
||||
|
||||
import os
|
||||
import stat
|
||||
import re
|
||||
try:
|
||||
from email.utils import parsedate_tz, mktime_tz
|
||||
except ImportError:
|
||||
from email.Utils import parsedate_tz, mktime_tz
|
||||
from wsgiref.util import FileWrapper
|
||||
|
||||
from django.core.files.base import File
|
||||
from django.http import StreamingHttpResponse, HttpResponseNotModified
|
||||
from django.utils.http import http_date
|
||||
|
||||
|
||||
def sendfile(request, filename, **kwargs):
|
||||
# Respect the If-Modified-Since header.
|
||||
statobj = os.stat(filename)
|
||||
|
||||
if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
|
||||
statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]):
|
||||
return HttpResponseNotModified()
|
||||
|
||||
response = StreamingHttpResponse(FileWrapper(open(filename, 'rb')))
|
||||
|
||||
response["Last-Modified"] = http_date(statobj[stat.ST_MTIME])
|
||||
return response
|
||||
|
||||
|
||||
def was_modified_since(header=None, mtime=0, size=0):
|
||||
"""
|
||||
Was something modified since the user last downloaded it?
|
||||
|
||||
header
|
||||
This is the value of the If-Modified-Since header. If this is None,
|
||||
I'll just return True.
|
||||
|
||||
mtime
|
||||
This is the modification time of the item we're talking about.
|
||||
|
||||
size
|
||||
This is the size of the item we're talking about.
|
||||
"""
|
||||
try:
|
||||
if header is None:
|
||||
raise ValueError
|
||||
matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", header,
|
||||
re.IGNORECASE)
|
||||
header_date = parsedate_tz(matches.group(1))
|
||||
if header_date is None:
|
||||
raise ValueError
|
||||
header_mtime = mktime_tz(header_date)
|
||||
header_len = matches.group(3)
|
||||
if header_len and int(header_len) != size:
|
||||
raise ValueError
|
||||
if mtime > header_mtime:
|
||||
raise ValueError
|
||||
except (AttributeError, ValueError, OverflowError):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
@ -2,6 +2,7 @@ from django.shortcuts import get_object_or_404
|
|||
from django.conf import settings
|
||||
|
||||
from wagtail.utils.sendfile import sendfile
|
||||
from wagtail.utils import sendfile_streaming_backend
|
||||
|
||||
from wagtail.wagtaildocs.models import Document, document_served
|
||||
|
||||
|
|
@ -15,7 +16,5 @@ def serve(request, document_id, document_filename):
|
|||
if hasattr(settings, 'SENDFILE_BACKEND'):
|
||||
return sendfile(request, doc.file.path, attachment=True, attachment_filename=doc.filename)
|
||||
else:
|
||||
# Fallback to simple backend if user hasn't specified SENDFILE_BACKEND (will crash by default)
|
||||
from sendfile.backends.simple import sendfile as simple_sendfile_backend
|
||||
|
||||
return sendfile(request, doc.file.path, attachment=True, attachment_filename=doc.filename, backend=simple_sendfile_backend)
|
||||
# Fallback to streaming backend if user hasn't specified SENDFILE_BACKEND
|
||||
return sendfile(request, doc.file.path, attachment=True, attachment_filename=doc.filename, backend=sendfile_streaming_backend.sendfile)
|
||||
|
|
|
|||
Loading…
Reference in a new issue