summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hellkamp <marc@gsites.de>2014-02-06 09:55:37 -0600
committerMarcel Hellkamp <marc@gsites.de>2014-02-06 09:56:10 -0600
commit4f6f71b4a2b06be0757f10a1af53a9b849a534dc (patch)
treed839ecae8ce19d52da72efe0e4dc9b8c129067b7
parent58d009e5921670f7b99300cdc0e6287d73351852 (diff)
downloadbottle-4f6f71b4a2b06be0757f10a1af53a9b849a534dc.tar.gz
fix 582: Unnecessary lowercasing in FileUpload.filename
-rw-r--r--bottle.py24
-rw-r--r--test/test_fileupload.py8
2 files changed, 20 insertions, 12 deletions
diff --git a/bottle.py b/bottle.py
index e6c5244..4b937d0 100644
--- a/bottle.py
+++ b/bottle.py
@@ -42,6 +42,8 @@ from datetime import date as datedate, datetime, timedelta
from tempfile import TemporaryFile
from traceback import format_exc, print_exc
from inspect import getargspec
+from unicodedata import normalize
+
try: from simplejson import dumps as json_dumps, loads as json_lds
except ImportError: # pragma: no cover
@@ -2258,19 +2260,21 @@ class FileUpload(object):
@cached_property
def filename(self):
''' Name of the file on the client file system, but normalized to ensure
- file system compatibility (lowercase, no whitespace, no path
- separators, no unsafe characters, ASCII only). An empty filename
- is returned as 'empty'.
+ file system compatibility. An empty filename is returned as 'empty'.
+
+ Only ASCII letters, digits, dashes, underscores and dots are
+ allowed in the final filename. Accents are removed, if possible.
+ Whitespace is replaced by a single dash. Leading or tailing dots
+ or dashes are removed. The filename is limited to 255 characters.
'''
- from unicodedata import normalize #TODO: Module level import?
fname = self.raw_filename
- if isinstance(fname, unicode):
- fname = normalize('NFKD', fname).encode('ASCII', 'ignore')
- fname = fname.decode('ASCII', 'ignore')
+ if not isinstance(fname, unicode):
+ fname = fname.decode('utf8', 'ignore')
+ fname = normalize('NFKD', fname).encode('ASCII', 'ignore').decode('ASCII')
fname = os.path.basename(fname.replace('\\', os.path.sep))
- fname = re.sub(r'[^a-zA-Z0-9-_.\s]', '', fname).strip().lower()
- fname = re.sub(r'[-\s]+', '-', fname.strip('.').strip())
- return fname or 'empty'
+ fname = re.sub(r'[^a-zA-Z0-9-_.\s]', '', fname).strip()
+ fname = re.sub(r'[-\s]+', '-', fname).strip('.-')
+ return fname[:255] or 'empty'
def _copy_file(self, fp, chunk_size=2**16):
read, write, offset = self.file.read, fp.write, self.file.tell()
diff --git a/test/test_fileupload.py b/test/test_fileupload.py
index c1a2130..13e8c7a 100644
--- a/test/test_fileupload.py
+++ b/test/test_fileupload.py
@@ -21,17 +21,21 @@ class TestFileUpload(unittest.TestCase):
def test_filename(self):
self.assertFilename('with space', 'with-space')
self.assertFilename('with more \t\n\r space', 'with-more-space')
- self.assertFilename('UpperCase', 'uppercase')
self.assertFilename('with/path', 'path')
self.assertFilename('../path', 'path')
self.assertFilename('..\\path', 'path')
self.assertFilename('..', 'empty')
self.assertFilename('.name.', 'name')
+ self.assertFilename('.name.cfg', 'name.cfg')
self.assertFilename(' . na me . ', 'na-me')
self.assertFilename('path/', 'empty')
- self.assertFilename(bottle.tob('ümläüts$'), 'mlts')
+ self.assertFilename(bottle.tob('ümläüts$'), 'umlauts')
self.assertFilename(bottle.touni('ümläüts$'), 'umlauts')
self.assertFilename('', 'empty')
+ self.assertFilename('a'+'b'*1337+'c', 'a'+'b'*254)
+
+ def test_preserve_case_issue_582(self):
+ self.assertFilename('UpperCase', 'UpperCase')
def test_save_buffer(self):
fu = FileUpload(open(__file__, 'rb'), 'testfile', __file__)