Skip to main content

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

Project description

Bitbucket Pipelines license status version Python version django version black

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.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 overriden 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-file
  • pip 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, resource_url: str):
    obj_qs = MyModel.objects.filter(my_file=resource_url)
    if not obj_qs.exists():
        return HttpResponseNotFound()
    if not attachment_qs.filter(user=request.user).exists():
        return HttpResponseForbidden()

    return get_sendfile_response(request, resource_url)

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, resource_url):
        obj_qs = MyModel.objects.filter(my_file=resource_url)
        if not obj_qs.exists():
            return HttpResponseNotFound()
        if not attachment_qs.filter(user=request.user).exists():
            return HttpResponseForbidden()

        return get_sendfile_response(request, resource_url)

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.
    • 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.2.0.tar.gz (5.3 kB view details)

Uploaded Source

Built Distribution

File details

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

File metadata

File hashes

Hashes for django_reverse_proxy_send_file-1.2.0.tar.gz
Algorithm Hash digest
SHA256 cbc67b8d6b06b46ed0c895d281ce344a58d61fd35557f1b4b2a4fa6203baeaa9
MD5 13cc1806f08cb684dc61882b51e1cc77
BLAKE2b-256 d7951a06b0c194c95da074112124806b20b9d7ef2e4f8d560ce7c35d6c71bb6b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for django_reverse_proxy_send_file-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0a36e1e4cccd062afc282a88cd3da77064d537f24859af72a329f9405f810a9c
MD5 4c18429e3d5083df7f5263edc14a1b27
BLAKE2b-256 830278982e6c79d790154da631673b4f1d652ce69cbccf9260bd35bf3c3ffa19

See more details on using hashes here.

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