From 300e24dbde28a3ad9c20fd8da529586248f3dbe1 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Sun, 22 Apr 2018 16:34:07 +0200 Subject: [PATCH] Ensure we return correct paths when using Apache as a reverse proxy --- api/funkwhale_api/music/views.py | 41 ++++++++++++++++++++++---------- api/tests/music/test_views.py | 25 +++++++++++++++++++ deploy/env.prod.sample | 4 ++++ 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py index 890cc2578..af063da46 100644 --- a/api/funkwhale_api/music/views.py +++ b/api/funkwhale_api/music/views.py @@ -205,6 +205,25 @@ class TrackViewSet( return Response(serializer.data) +def get_file_path(audio_file): + t = settings.REVERSE_PROXY_TYPE + if t == 'nginx': + # we have to use the internal locations + try: + path = audio_file.url + except AttributeError: + # a path was given + path = '/music' + audio_file + return settings.PROTECT_FILES_PATH + path + if t == 'apache2': + try: + path = audio_file.path + except AttributeError: + # a path was given + path = audio_file + return path + + class TrackFileViewSet(viewsets.ReadOnlyModelViewSet): queryset = (models.TrackFile.objects.all().order_by('-id')) serializer_class = serializers.TrackFileSerializer @@ -243,24 +262,20 @@ class TrackFileViewSet(viewsets.ReadOnlyModelViewSet): library_track = qs.get(pk=library_track.pk) library_track.download_audio() audio_file = library_track.audio_file - file_path = '{}{}'.format( - settings.PROTECT_FILES_PATH, - audio_file.url) + file_path = get_file_path(audio_file) mt = library_track.audio_mimetype elif audio_file: - file_path = '{}{}'.format( - settings.PROTECT_FILES_PATH, - audio_file.url) + file_path = get_file_path(audio_file) elif f.source and f.source.startswith('file://'): - file_path = '{}{}'.format( - settings.PROTECT_FILES_PATH + '/music', - f.serve_from_source_path) + file_path = get_file_path(f.serve_from_source_path) response = Response() filename = f.filename - if settings.REVERSE_PROXY_TYPE == 'apache2': - response['X-Sendfile'] = file_path - elif settings.REVERSE_PROXY_TYPE == 'nginx': - response['X-Accel-Redirect'] = file_path + mapping = { + 'nginx': 'X-Accel-Redirect', + 'apache2': 'X-Sendfile', + } + file_header = mapping[settings.REVERSE_PROXY_TYPE] + response[file_header] = file_path filename = "filename*=UTF-8''{}".format( urllib.parse.quote(filename)) response["Content-Disposition"] = "attachment; {}".format(filename) diff --git a/api/tests/music/test_views.py b/api/tests/music/test_views.py index 5863e7b07..5d7589af0 100644 --- a/api/tests/music/test_views.py +++ b/api/tests/music/test_views.py @@ -76,6 +76,31 @@ def test_can_serve_track_file_as_remote_library_deny_not_following( assert response.status_code == 403 +def test_serve_file_apache(factories, api_client, settings): + settings.PROTECT_AUDIO_FILES = False + settings.REVERSE_PROXY_TYPE = 'apache2' + tf = factories['music.TrackFile']() + response = api_client.get(tf.path) + + assert response.status_code == 200 + assert response['X-Sendfile'] == tf.audio_file.path + + +def test_serve_file_apache_in_place(factories, api_client, settings): + settings.PROTECT_AUDIO_FILES = False + settings.REVERSE_PROXY_TYPE = 'apache2' + settings.MUSIC_DIRECTORY_PATH = '/music' + settings.MUSIC_DIRECTORY_SERVE_PATH = '/host/music' + track_file = factories['music.TrackFile']( + in_place=True, + source='file:///music/test.ogg') + + response = api_client.get(track_file.path) + + assert response.status_code == 200 + assert response['X-Sendfile'] == '/host/music/test.ogg' + + def test_can_proxy_remote_track( factories, settings, api_client, r_mock): settings.PROTECT_AUDIO_FILES = False diff --git a/deploy/env.prod.sample b/deploy/env.prod.sample index f33b06876..54f2e1ef0 100644 --- a/deploy/env.prod.sample +++ b/deploy/env.prod.sample @@ -41,6 +41,10 @@ FUNKWHALE_API_PORT=5000 # your instance FUNKWHALE_URL=https://yourdomain.funwhale +# Depending on the reverse proxy used in front of your funkwhale instance, +# the API will use different kind of headers to serve audio files +# Allowed values: nginx, apache2 +REVERSE_PROXY_TYPE=nginx # API/Django configuration