Skip to main content

Storage and View to send X-Accel-Redirect (or X-Sendfile) header to nginx (or apache) reverse-proxy

Project description

django-reverse-proxy-send-file

Sumary

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.ReverseProxySendFileStorageFileSystemStorage 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 overriden base_url on any storage class

The ReverseProxySendFileView class handle GET request and return an empty response with nginx's X-Accel-Redirect header to order nginx to return the file at given path. The REVERSE_PROXY_SENDFILE_MEDIA_ROOT setting must be defined in the nginx context si it can find the file

The ReverseProxySendFileView can be overrided to implement a custom check_permission method which verify is the current user is allowed to download the resource.

Installation

Install the django-reverse-proxy-send-file pypi package. ex:

  • poetry add django-reverse-proxy-send-file
  • pip install django-reverse-proxy-send-file

Usage

See example section bellow

Settings

REVERSE_PROXY_SENDFILE_MEDIA_ROOT

Default to django's MEDIA_ROOT

Base path in django's context where to store media files when uploaded (used by Storage class)

REVERSE_PROXY_SENDFILE_MEDIA_URL

Default to "smedia/"

URL that handle the resources that should be served by the reverse proxy.

REVERSE_PROXY_SENDFILE_REVERSE_PROXY_ROOT

Default to "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

Default to "nginx"

Possible values: "nginx" or "apache"

nginx mode will use X-Accel-Redirect header whereas apache mode will use X-Sendfile

REVERSE_PROXY_SENDFILE_HEADER_NAME

Default to None

Enter a custom header name. If set this header will be used regardless REVERSE_PROXY_SENDFILE_MODE setting.

REVERSE_PROXY_SENDFILE_DEBUG_SERVE_RESOURCE

Default to 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 ReverseProxySendFileStorageFileSystemStorage

class MyModel(models.Model):
    ...
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    my_file = models.FileField(
        "My file",
        upload_to="my_files/",
        storage=ReverseProxySendFileStorageFileSystemStorage(),
    )
    ...

views.py

from django.http import Http404

from reverse_proxy_send_file.views import ReverseProxySendFileView

class ReverseProxySendFileMyFileView(ReverseProxySendFileView):
    def check_permission(self, request, resource_url, *args, **kwargs):
        obj_qs = MyModel.objects.filter(my_file=resource_url)
        if not obj_qs.exists():
            raise Http404()
        return obj_qs.filter(user=request.user).exists()

urls.py

from django.conf import settings
from views import ReverseProxySendFileMyFileView

urlpatterns = [
    ...
    re_path(
        settings.REVERSE_PROXY_SENDFILE_MEDIA_URL + "(?P<resource_url>my_files/.*)$",
        views.ReverseProxySendFileMyFileView.as_view(),
        name="reverse_proxy_send_file",
    ),
    ...
]
  1. User upload file. The file is stored in /django_path/to/smedia/my_files/blop.pdf
  2. User access /smedia/my_files/blop.pdf
  3. A django request is performed and it check file access permission for current user (in check_permission).
    • 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

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_reverse_proxy_send_file-1.0.0.tar.gz (4.8 kB view details)

Uploaded Source

Built Distribution

File details

Details for the file django_reverse_proxy_send_file-1.0.0.tar.gz.

File metadata

File hashes

Hashes for django_reverse_proxy_send_file-1.0.0.tar.gz
Algorithm Hash digest
SHA256 2889a1ff9de449438ef0aab17d55eb7daa00a9691d3299593d9e4a095afef51a
MD5 b4856a749b2d074ed0be43b86ccd0dc7
BLAKE2b-256 b5a5040127fb2cfce87b70ee1e8e885615d1b4836a26ebecbbc291fcd300cccb

See more details on using hashes here.

Provenance

File details

Details for the file django_reverse_proxy_send_file-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_reverse_proxy_send_file-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eb111f82e0c98bc7aac2529716835852e5f4adb4f8948c753940866ad05eb995
MD5 443654294709dac3d5dfbd7947c56d29
BLAKE2b-256 0f9654418ee9daa062ce16b2489392deae62e19d2ae6799ba6150a957ee006f2

See more details on using hashes here.

Provenance

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page