From f0bea39d6a09ac09579f6fbdceac3477503e9601 Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Tue, 1 Oct 2019 10:57:14 +0200
Subject: [PATCH] Fix #924: in-place imported files not playing under nginx
 when filename contains ? or %

---
 api/funkwhale_api/music/views.py |  4 +++-
 api/tests/music/test_views.py    | 25 +++++++++++++++++++++++--
 changes/changelog.d/924.bugfix   |  1 +
 3 files changed, 27 insertions(+), 3 deletions(-)
 create mode 100644 changes/changelog.d/924.bugfix

diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py
index 4783a8d45..c0effbac2 100644
--- a/api/funkwhale_api/music/views.py
+++ b/api/funkwhale_api/music/views.py
@@ -1,6 +1,6 @@
 import datetime
 import logging
-import urllib
+import urllib.parse
 
 from django.conf import settings
 from django.db import transaction
@@ -321,6 +321,8 @@ def get_file_path(audio_file):
             path = "/music" + audio_file.replace(prefix, "", 1)
         if path.startswith("http://") or path.startswith("https://"):
             return (settings.PROTECT_FILES_PATH + "/media/" + path).encode("utf-8")
+        # needed to serve files with % or ? chars
+        path = urllib.parse.quote(path)
         return (settings.PROTECT_FILES_PATH + path).encode("utf-8")
     if t == "apache2":
         try:
diff --git a/api/tests/music/test_views.py b/api/tests/music/test_views.py
index 4a423ddb1..0339437d4 100644
--- a/api/tests/music/test_views.py
+++ b/api/tests/music/test_views.py
@@ -226,13 +226,34 @@ def test_serve_file_in_place(
     assert response[headers[proxy]] == expected
 
 
+def test_serve_file_in_place_nginx_encode_url(
+    factories, api_client, preferences, settings
+):
+    preferences["common__api_authentication_required"] = False
+    settings.PROTECT_FILE_PATH = "/_protected/music"
+    settings.REVERSE_PROXY_TYPE = "nginx"
+    settings.MUSIC_DIRECTORY_PATH = "/app/music"
+    settings.MUSIC_DIRECTORY_SERVE_PATH = "/app/music"
+    upload = factories["music.Upload"](
+        in_place=True,
+        import_status="finished",
+        source="file:///app/music/hello/world%?.mp3",
+        library__privacy_level="everyone",
+    )
+    response = api_client.get(upload.track.listen_url)
+    expected = "/_protected/music/hello/world%25%3F.mp3"
+
+    assert response.status_code == 200
+    assert response["X-Accel-Redirect"] == expected
+
+
 @pytest.mark.parametrize(
     "proxy,serve_path,expected",
     [
         ("apache2", "/host/music", "/host/music/hello/worldéà.mp3"),
         ("apache2", "/app/music", "/app/music/hello/worldéà.mp3"),
-        ("nginx", "/host/music", "/_protected/music/hello/worldéà.mp3"),
-        ("nginx", "/app/music", "/_protected/music/hello/worldéà.mp3"),
+        ("nginx", "/host/music", "/_protected/music/hello/world%C3%A9%C3%A0.mp3"),
+        ("nginx", "/app/music", "/_protected/music/hello/world%C3%A9%C3%A0.mp3"),
     ],
 )
 def test_serve_file_in_place_utf8(
diff --git a/changes/changelog.d/924.bugfix b/changes/changelog.d/924.bugfix
new file mode 100644
index 000000000..c5986581a
--- /dev/null
+++ b/changes/changelog.d/924.bugfix
@@ -0,0 +1 @@
+Fixed in-place imported files not playing under nginx when filename contains ? or % (#924)
-- 
GitLab