From 32a438e76cdec017e527fa4c22735714c3308b4b Mon Sep 17 00:00:00 2001 From: Hironsan Date: Mon, 31 May 2021 13:59:12 +0900 Subject: [PATCH] Add middleware for range request --- backend/api/middleware.py | 35 +++++++++++++++++++++++++++++++++++ backend/app/settings.py | 3 +++ 2 files changed, 38 insertions(+) create mode 100644 backend/api/middleware.py diff --git a/backend/api/middleware.py b/backend/api/middleware.py new file mode 100644 index 00000000..83b7f5f8 --- /dev/null +++ b/backend/api/middleware.py @@ -0,0 +1,35 @@ +import os + +from django.utils.deprecation import MiddlewareMixin + + +class RangesMiddleware(MiddlewareMixin): + """Quick solution. See: + https://stackoverflow.com/questions/14324250/byte-ranges-in-django/35928017#35928017 + """ + + def process_response(self, request, response): + if response.status_code != 200 or not hasattr(response, 'file_to_stream'): + return response + http_range = request.META.get('HTTP_RANGE') + if not (http_range and http_range.startswith('bytes=') and http_range.count('-') == 1): + return response + if_range = request.META.get('HTTP_IF_RANGE') + if if_range and if_range != response.get('Last-Modified') and if_range != response.get('ETag'): + return response + f = response.file_to_stream + statobj = os.fstat(f.fileno()) + start, end = http_range.split('=')[1].split('-') + if not start: # requesting the last N bytes + start = max(0, statobj.st_size - int(end)) + end = '' + start, end = int(start or 0), int(end or statobj.st_size - 1) + assert 0 <= start < statobj.st_size, (start, statobj.st_size) + end = min(end, statobj.st_size - 1) + f.seek(start) + old_read = f.read + f.read = lambda n: old_read(min(n, end + 1 - f.tell())) + response.status_code = 206 + response['Content-Length'] = end + 1 - start + response['Content-Range'] = 'bytes %d-%d/%d' % (start, end, statobj.st_size) + return response diff --git a/backend/app/settings.py b/backend/app/settings.py index 67f6ef76..21851751 100644 --- a/backend/app/settings.py +++ b/backend/app/settings.py @@ -88,6 +88,9 @@ MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', ] +if DEBUG: + MIDDLEWARE.append('api.middleware.RangesMiddleware') + ROOT_URLCONF = 'app.urls' TEMPLATES = [