Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added no_file_check to sendfile for remote proxy case #20

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 32 additions & 16 deletions sendfile/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ def _get_sendfile():



def sendfile(request, filename, attachment=False, attachment_filename=None, mimetype=None, encoding=None):
'''
create a response to send file using backend configured in SENDFILE_BACKEND
def sendfile(request, filename, attachment=False, attachment_filename=None, mimetype=None, encoding=None, no_file_check = False):
'''create a response to send file using backend configured in
SENDFILE_BACKEND

If attachment is True the content-disposition header will be set.
This will typically prompt the user to download the file, rather
Expand All @@ -45,23 +45,38 @@ def sendfile(request, filename, attachment=False, attachment_filename=None, mime
False: No content-disposition filename
String: Value used as filename

If no mimetype or encoding are specified, then they will be guessed via the
filename (using the standard python mimetypes module)
If no mimetype or encoding are specified, then they will be
guessed via the filename (using the standard python mimetypes
module)

If no_file_Check is true, sendfile() will check that the file
exists on the filesystem where stated. If no_file_check is False,
then sendfile() will simply encode the path without checking for
its existence. In this case it also won't set the Content-Length
or Content-Encoding header, so your surrounding proxy will need to
do that as needed. This mode can be useful when using sendfile()
under a proxy atop a remote store (eg S3).

'''
_sendfile = _get_sendfile()

if not os.path.exists(filename):
if not no_file_check and not os.path.exists(filename):
from django.http import Http404
raise Http404('"%s" does not exist' % filename)

guessed_mimetype, guessed_encoding = guess_type(filename)
if mimetype is None:
if guessed_mimetype:
mimetype = guessed_mimetype
else:
mimetype = 'application/octet-stream'

response = _sendfile(request, filename, mimetype=mimetype)

if not no_file_check:
guessed_mimetype, guessed_encoding = guess_type(filename)
if mimetype is None:
if guessed_mimetype:
mimetype = guessed_mimetype
else:
mimetype = 'application/octet-stream'
else:
mimetype = 'application/octet-stream'

response = _sendfile(request, filename, mimetype=mimetype,
no_file_check=no_file_check)
if attachment:
if attachment_filename is None:
attachment_filename = os.path.basename(filename)
Expand All @@ -82,9 +97,10 @@ def sendfile(request, filename, attachment=False, attachment_filename=None, mime
parts.append('filename*=UTF-8\'\'%s' % quoted_filename)
response['Content-Disposition'] = '; '.join(parts)

response['Content-length'] = os.path.getsize(filename)
if not no_file_check:
response['Content-length'] = os.path.getsize(filename)
response['Content-Type'] = mimetype
if not encoding:
if not encoding and not no_file_check:
encoding = guessed_encoding
if encoding:
response['Content-Encoding'] = encoding
Expand Down
16 changes: 12 additions & 4 deletions sendfile/backends/_internalredirect.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
from django.conf import settings
import os.path

def _convert_file_to_url(filename):
def _convert_file_to_url(filename, no_file_check = False):
"""In the normal case (no_file_check is False) reduce the filepath
against the filesystem and content root. If no_file_check is
True, then don't do any of that and instead assume that the path
passed is correct and in its ultimate form.

"""
if no_file_check: # We already a priori know that the path is
# correct and in its final form.
return filename
relpath = os.path.relpath(filename, settings.SENDFILE_ROOT)

url = [settings.SENDFILE_URL]

while relpath:
relpath, head = os.path.split(relpath)
url.insert(1, head)

return u'/'.join(url)

return u'/'.join(url) # Note: xlates from os.path.sep to '/'
4 changes: 2 additions & 2 deletions sendfile/backends/mod_wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

def sendfile(request, filename, **kwargs):
response = HttpResponse()
response['Location'] = _convert_file_to_url(filename)
response['Location'] = _convert_file_to_url(
filename, no_file_check = kwargs.get ("no_file_check", False))
# need to destroy get_host() to stop django
# rewriting our location to include http, so that
# mod_wsgi is able to do the internal redirect
request.get_host = lambda: ''

return response

3 changes: 2 additions & 1 deletion sendfile/backends/nginx.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

def sendfile(request, filename, **kwargs):
response = HttpResponse()
url = _convert_file_to_url(filename)
url = _convert_file_to_url(
filename, no_file_check = kwargs.get ("no_file_check", False))
response['X-Accel-Redirect'] = url.encode('utf-8')

return response
12 changes: 6 additions & 6 deletions sendfile/backends/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ 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]):
if not was_modified_since(
request.META.get('HTTP_IF_MODIFIED_SINCE'),
statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]):
return HttpResponseNotModified()


response = HttpResponse(File(file(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?
Expand Down Expand Up @@ -52,4 +53,3 @@ def was_modified_since(header=None, mtime=0, size=0):
except (AttributeError, ValueError, OverflowError):
return True
return False

2 changes: 0 additions & 2 deletions sendfile/backends/xsendfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@
def sendfile(request, filename, **kwargs):
response = HttpResponse()
response['X-Sendfile'] = unicode(filename).encode('utf-8')

return response