diff --git a/3rd_party_apps/sendfile/__init__.py b/3rd_party_apps/sendfile/__init__.py new file mode 100644 index 0000000000..9d7ce68ad2 --- /dev/null +++ b/3rd_party_apps/sendfile/__init__.py @@ -0,0 +1,51 @@ +VERSION = (0, 1, 1) +__version__ = '.'.join(map(str, VERSION)) + +import os.path +from mimetypes import guess_type + +def _lazy_load(fn): + _cached = [] + def _decorated(): + if not _cached: + _cached.append(fn()) + return _cached[0] + return _decorated + + +@_lazy_load +def _get_sendfile(): + from django.utils.importlib import import_module + from django.conf import settings + from django.core.exceptions import ImproperlyConfigured + + backend = getattr(settings, 'SENDFILE_BACKEND', 'sendfile.backends.simple') + if not backend: + raise ImproperlyConfigured('You must specify a valued for SENDFILE_BACKEND') + module = import_module(backend) + return module.sendfile + + + +def sendfile(request, filename, attachment=False, attachment_filename=None): + ''' + create a response to send file using backend configured in SENDFILE_BACKEND + + if attachment is True the content-disposition header will be set with either + the filename given or else the attachment_filename (of specified). This + will typically prompt the user to download the file, rather than view it. + ''' + _sendfile = _get_sendfile() + response = _sendfile(request, filename) + if attachment: + attachment_filename = attachment_filename or os.path.basename(filename) + response['Content-Disposition'] = 'attachment; filename=%s' % attachment_filename + + response['Content-length'] = os.path.getsize(filename) + + content_type = guess_type(filename)[0] + if content_type is None: + content_type = "application/octet-stream" + response['Content-Type'] = content_type + + return response diff --git a/3rd_party_apps/sendfile/backends/__init__.py b/3rd_party_apps/sendfile/backends/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/3rd_party_apps/sendfile/backends/chunked_file.py b/3rd_party_apps/sendfile/backends/chunked_file.py new file mode 100644 index 0000000000..0bf1a95610 --- /dev/null +++ b/3rd_party_apps/sendfile/backends/chunked_file.py @@ -0,0 +1,13 @@ +from django.http import HttpResponse +from django.core.files.uploadedfile import SimpleUploadedFile + +def sendfile(request, filename): + return = HttpResponse(IterFile(filename)) + +class IterFile(object): + def __init__(self, filename): + self.file = SimpleUploadedFile(name=filename, content=open(filename).read()) + + def __iter__(self): + return self.file.chunks() + diff --git a/3rd_party_apps/sendfile/backends/development.py b/3rd_party_apps/sendfile/backends/development.py new file mode 100644 index 0000000000..5fa2221188 --- /dev/null +++ b/3rd_party_apps/sendfile/backends/development.py @@ -0,0 +1,15 @@ +from django.views.static import serve + +import os.path + +def sendfile(request, filename): + ''' + Send file using django dev static file server. + + DO NOT USE IN PRODUCTION + this is only to be used when developing and is provided + for convenience only + ''' + dirname = os.path.dirname(filename) + basename = os.path.basename(filename) + return serve(request, basename, dirname) diff --git a/3rd_party_apps/sendfile/backends/mod_wsgi.py b/3rd_party_apps/sendfile/backends/mod_wsgi.py new file mode 100644 index 0000000000..82cf55c806 --- /dev/null +++ b/3rd_party_apps/sendfile/backends/mod_wsgi.py @@ -0,0 +1,30 @@ +from django.http import HttpResponse + +from django.conf import settings +import os.path + +def _convert_file_to_url(filename): + # CURRENTLY NOT WORKING + # mod_wsgi wants a relative URL not a filename + # so apache does an internal redirect + + 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) + +def sendfile(request, filename): + response = HttpResponse() + response['Location'] = _convert_file_to_url(filename) + # 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 + diff --git a/3rd_party_apps/sendfile/backends/simple.py b/3rd_party_apps/sendfile/backends/simple.py new file mode 100644 index 0000000000..d65e8d6b9a --- /dev/null +++ b/3rd_party_apps/sendfile/backends/simple.py @@ -0,0 +1,6 @@ +from django.core.servers.basehttp import FileWrapper +from django.http import HttpResponse + +def sendfile(request, filename): + wrapper = FileWrapper(file(filename)) + return HttpResponse(wrapper) diff --git a/3rd_party_apps/sendfile/backends/xsendfile.py b/3rd_party_apps/sendfile/backends/xsendfile.py new file mode 100644 index 0000000000..5bba6a3759 --- /dev/null +++ b/3rd_party_apps/sendfile/backends/xsendfile.py @@ -0,0 +1,8 @@ +from django.http import HttpResponse + +def sendfile(request, filename): + response = HttpResponse() + response['X-Sendfile'] = filename + + return response +