Browse Source

Quote filenames in Location header on redirect

When we redirect the user to the "correct" file name this name should
end up quoted in the header, else we would end up in an infinite
redirect loop.
Sebastian Lohff 6 months ago
parent
commit
3249647c0b
3 changed files with 23 additions and 2 deletions
  1. 2
    0
      ChangeLog
  2. 1
    1
      servefile/servefile.py
  3. 20
    1
      tests/test_servefile.py

+ 2
- 0
ChangeLog View File

@@ -11,6 +11,8 @@ Unreleased
11 11
 	  wished the ports can be set from outside by specifying the
12 12
 	  environment variables SERVEFILE_DEFAULT_PORT and
13 13
 	  SERVEFILE_SECONDARY_PORT
14
+	* fixed broken redirect when filename contained umlauts or other characters
15
+	  that should have been quoted
14 16
 
15 17
 
16 18
 2020-10-30 v0.5.1

+ 1
- 1
servefile/servefile.py View File

@@ -60,7 +60,7 @@ class FileBaseHandler(BaseHTTPServer.BaseHTTPRequestHandler):
60 60
 			fileName = self.fileName
61 61
 		if unquote(self.path) != "/" + fileName:
62 62
 			self.send_response(302)
63
-			self.send_header('Location', '/' + fileName)
63
+			self.send_header('Location', '/' + quote(fileName))
64 64
 			self.end_headers()
65 65
 			return True
66 66
 		return False

+ 20
- 1
tests/test_servefile.py View File

@@ -1,3 +1,4 @@
1
+# -*- coding: utf-8 -*-
1 2
 import io
2 3
 import os
3 4
 import pytest
@@ -14,9 +15,11 @@ import urllib3
14 15
 
15 16
 if sys.version_info.major >= 3:
16 17
     from pathlib import Path
18
+    from urllib.parse import quote
17 19
     connrefused_exc = ConnectionRefusedError
18 20
 else:
19 21
     from pathlib2 import Path
22
+    from urllib import quote
20 23
     connrefused_exc = socket.error
21 24
 
22 25
 
@@ -162,6 +165,21 @@ def test_redirect_and_download(run_servefile, datadir):
162 165
     check_download(data, fname='testfile')
163 166
 
164 167
 
168
+def test_redirect_and_download_with_umlaut(run_servefile, datadir):
169
+    data = "NÖÖT NÖÖT"
170
+    filename = "tästføile"
171
+    p = datadir({filename: data}) / filename
172
+    run_servefile(str(p))
173
+
174
+    # redirect
175
+    r = make_request(allow_redirects=False)
176
+    assert r.status_code == 302
177
+    assert r.headers.get('Location') == '/{}'.format(quote(filename))
178
+
179
+    # normal download
180
+    check_download(data, fname=filename)
181
+
182
+
165 183
 def test_specify_port(run_servefile, datadir):
166 184
     data = "NOOT NOOT"
167 185
     p = datadir({'testfile': data}) / 'testfile'
@@ -210,6 +228,7 @@ def test_serve_directory(run_servefile, datadir):
210 228
         'bar': {'thisisaverylongfilenamefortestingthatthisstillworksproperly': 'jup!'},
211 229
         'noot': 'still data in here',
212 230
         'bigfile': 'x' * (10 * 1024 ** 2),
231
+        'möwe': 'KRAKRAKRAKA',
213 232
     }
214 233
     p = datadir(d)
215 234
     run_servefile([str(p), '-l'])
@@ -219,7 +238,7 @@ def test_serve_directory(run_servefile, datadir):
219 238
     for path in '/', '/../':
220 239
         r = make_request(path)
221 240
         for k in d:
222
-            assert k in r.text
241
+            assert quote(k) in r.text
223 242
 
224 243
     for fname, content in d['foo'].items():
225 244
         check_download(content, '/foo/' + fname)

Loading…
Cancel
Save