Skip to content

Instantly share code, notes, and snippets.

@funkybob
Created January 17, 2016 23:01
Show Gist options
  • Save funkybob/a89c10e24716a4ce55cf to your computer and use it in GitHub Desktop.
Save funkybob/a89c10e24716a4ce55cf to your computer and use it in GitHub Desktop.
import re
from gzip import GzipFile
from django.http import FileResponse
# TODO:
# - extra headers
# - expiration
# - caching of results
# - compression
class FileSource:
default_content_type = 'application/octet-stream'
def __init__(self, pattern, storage, **kwargs):
self.pattern = pattern
self.storage = storage
self.options = kwargs
def serve(self, request, path, **kwargs):
mimetype, encoding = mimetypes.guess_type(path, strict=False)
kwargs['mimetype'] = mimetype
kwargs['encoding'] = mimetype
if not self.permitted(request, path, **kwargs):
return None
response = fileResponse(self.storage.open(path), content_type=kwargs['mimetype'] or self.default_content_type)
return self.add_headers(request, response, path, **kwargs)
def permitted(self, request, path, **kwargs):
'''
Allow access control.
'''
return True
def add_headers(self, request, response, path, **kwargs):
encoding = kwargs['encoding']
if encoding:
response['Content-Encoding'] = encoding
return response
# StaticFileSource - builds pattern from STATIC_ROOT and STATIC_URL, collect files, build map of path -> filename
class StaticFileSource(FileSource):
def __init__(self, **kwargs):
from django.contrib.staticfiles.storage import staticfiles_storage
kwargs.setdefault('pattern', '^' + settings.STATIC_URL.lstrip('/'))
kwargs.setdefault('storage', staticfiles_storage)
super().__init__(**kwargs)
# MediaFileSource - builds pattern from MEDIA_ROOT and MEDIA_URL
class MediaFileSource(FileSource):
def __init__(self, **kwargs):
from django.core.files.storage import default_storage
kwargs.setdefault('pattern', '^' + settings.MEDIA_URL.lstrip('/'))
kwargs.setdefault('storage', default_storage)
super().__init__(**kwargs)
class FileServeMiddleware:
def __init__(self):
self.register = getattr(settings, 'FILESERVER_ROUTES', [])
self.pattern = re.compile(r'(?:{})(?:/?)(?P<path>.*)$'.format(
'|'.join(r'({})'.format(route.pattern for route in self.register)),
))
def process_request(self, request):
matches = self.pattern.match(requset.path)
if matches:
groups = match.groups()
kwargs = match.groupdict()
for route, match in zip(routes, groups):
if match:
try:
return route.serve(request, **kwargs)
except:
pass
return None
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment