django-reverse-proxy-send-file
Summary
This package help writing views which use the X-Accel-Redirect header to have nginx serving files but still allow a permission check at django's side
Intro
The storage.ReverseProxySendFileFileSystemStorage class is a drop-in replacement of django's FileSystemStorage which make FileField (or ImageField) url to use the REVERSE_PROXY_SENDFILE_MEDIA_URL settings base url instead of MEDIA_URL
The storage.ReverseProxySendFileStorageMixin allow you to apply the overrode base_url on any storage class
The get_sendfile_response return HTTP response to tell reverse proxy what to do.
Installation
Install the django-reverse-proxy-send-file pypi package.
ex:
poetry add django-reverse-proxy-send-filepip install django-reverse-proxy-send-file
Usage
See example section bellow
Settings
| Name | Default | Description |
|---|---|---|
| REVERSE_PROXY_SENDFILE_MEDIA_ROOT | MEDIA_ROOT | Base path in django's context where to store media files when uploaded (used by Storage class) |
| REVERSE_PROXY_SENDFILE_MEDIA_URL | "/smedia/" |
URL that handle the resources that should be served by the reverse proxy. |
| REVERSE_PROXY_SENDFILE_REVERSE_PROXY_ROOT | "smedia/" |
Base path in reverse-proxy's context which is sent back to reverse-proxy in header so it can find the file |
| REVERSE_PROXY_SENDFILE_MODE | "nginx" |
Possible values: "nginx" or "apache". nginx mode will use X-Accel-Redirect header.apache mode will use X-Sendfile |
| REVERSE_PROXY_SENDFILE_HEADER_NAME | None |
A custom header name. If set this header will be used regardless REVERSE_PROXY_SENDFILE_MODE setting. |
| REVERSE_PROXY_SENDFILE_DEBUG_SERVE_RESOURCE | True |
In django's DEBUG mode, the resource is directly served by the dev server. |
Exemple
settings.py
...
REVERSE_PROXY_SENDFILE_MEDIA_URL = "/smedia/"
REVERSE_PROXY_SENDFILE_MEDIA_ROOT = "/django_path/to/smedia/"
REVERSE_PROXY_SENDFILE_REVERSE_PROXY_ROOT = "/nginx_path/to/smedia/"
...
models.py
from django.contrib.auth.models import User
from reverse_proxy_send_file.storage import ReverseProxySendFileFileSystemStorage
class MyModel(models.Model):
...
user = models.ForeignKey(User, on_delete=models.CASCADE)
my_file = models.FileField(
"My file",
upload_to="my_files/",
storage=ReverseProxySendFileFileSystemStorage(),
)
...
views.py
Using function view
from django.http import Http404
from reverse_proxy_send_file.response import get_sendfile_response
def my_file_download_view(request, path: str):
obj_qs = MyModel.objects.filter(my_file=path)
if not obj_qs.exists():
return HttpResponseNotFound()
if not attachment_qs.filter(user=request.user).exists():
return HttpResponseForbidden()
return get_sendfile_response(request, path)
Using class based view
from django.http import Http404
from reverse_proxy_send_file.response import get_sendfile_response
class ReverseProxySendFileMyFileView(View):
def get(self, request, path):
obj_qs = MyModel.objects.filter(my_file=path)
if not obj_qs.exists():
return HttpResponseNotFound()
if not attachment_qs.filter(user=request.user).exists():
return HttpResponseForbidden()
return get_sendfile_response(request, path)
urls.py
from django.conf import settings
from views import ReverseProxySendFileMyFileView
from reverse_proxy_send_file.url import smedia_url
urlpatterns = [
...
re_path(
settings.REVERSE_PROXY_SENDFILE_MEDIA_URL.lstrip("/") + "(?P<path>my_files/.*)$",
views.ReverseProxySendFileMyFileView.as_view(),
name="reverse_proxy_send_file",
),
# or more concisely with smedia_url
smedia_url(
"my_files",
views.ReverseProxySendFileMyFileView.as_view(),
name="reverse_proxy_send_file",
# param_name = "something_else" to change the default "path"
),
...
]
- User upload file. The file is stored in
/django_path/to/smedia/my_files/blop.pdf - User access
/smedia/my_files/blop.pdf - A django request is performed and it check file access permission for current user.
-
- If the user is allowed return a HTTP response with header :
X-Accel-Redirect=/nginx_path/to/smedia/my_files/blop.pdf(Nginx will use it to send the file to the client) - If the file os not found return a
404 note found. - If the user id forbidden, return a
403 response forbidden
- If the user is allowed return a HTTP response with header :
smedia_url helper function
The smedia_url function is a helper to avoid verbose re_path.
There are several ways to use it:
- Pass just the base dir of you files :
urlpatterns = [
smedia_url(
"my_files",
views.ReverseProxySendFileMyFileView.as_view(),
),
]
- Pass the base dir with a custom param name to match view one
def my_file_download_view(request, resource_path: str):
...
urlpatterns = [
smedia_url(
"my_files",
my_file_download_view,
param_name="resource_path"
),
]
- Force specific re_path
def my_file_download_view(request, path: str, filename: str):
...
urlpatterns = [
smedia_url(
None,
my_file_download_view,
re_path="(?P<path>.*+*?)/(?P<filename>.*)"
),
]
- Override secure media URL
urlpatterns = [
smedia_url(
"my_files",
my_file_download_view,
smedia_url="/other-smedia/"
),
]
Setup dev environnement
# install dev dependencies
poetry install --no-root
# install git pre-commit
pre-commit install
Run tests
Use tox command to run all tests on all supported python versions
Examples:
tox
tox -e py38-django40
tox -f py39
Build package and publish on PyPI
Change version number in pyproject.toml
poetry build
poetry publish
Release files for django-reverse-proxy-send-file 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_reverse_proxy_send_file-2.0.0.tar.gz | 5.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_reverse_proxy_send_file-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 12.2 kB
Release files / django_reverse_proxy_send_file-2.0.0.tar.gz
| Download URL | django_reverse_proxy_send_file-2.0.0.tar.gz |
|---|---|
| Size | 5.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e3e74bdee16800af8ec544bb7a3fa4d44cce021602bc30a48271ea03e380bca9
|
|
BLAKE2b-256 checksum How to use checksums |
c6486f3ddf3f15f22346b392131c5f13f5066749bf23a874f9ffe43fc568a8b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.8.4 CPython/3.12.7 Linux/6.12.4-arch1-1
|
Release files / django_reverse_proxy_send_file-2.0.0-py3-none-any.whl
| Download URL | django_reverse_proxy_send_file-2.0.0-py3-none-any.whl |
|---|---|
| Size | 6.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c01315d12c2bf5da60fa6bfcd46eea5a93a32dce898a8415d61febe10212dc72
|
|
BLAKE2b-256 checksum How to use checksums |
80eceaae225a4a60aeb98f87a7bb60052b0290a383b4cf6d9153afd0b75f107a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.8.4 CPython/3.12.7 Linux/6.12.4-arch1-1
|