Ticket #8593: 8593-dont-lowercase-uploaded-filenames-r9961.diff

File 8593-dont-lowercase-uploaded-filenames-r9961.diff, 7.1 KB (added by Ramiro Morales, 16 years ago)

Same patch but with two comments edited to be more accurate

  • django/utils/_os.py

    diff --git a/django/utils/_os.py b/django/utils/_os.py
    a b  
    2121            path = join(os.getcwdu(), path)
    2222        return normpath(path)
    2323
     24if os.name == 'nt':
     25    _normcase = lambda s: s.replace("/", "\\")
     26else:
     27    _normcase = normcase
     28
    2429def safe_join(base, *paths):
    2530    """
    2631    Joins one or more path components to the base path component intelligently.
     
    2934    The final path must be located inside of the base path component (otherwise
    3035    a ValueError is raised).
    3136    """
    32     # We need to use normcase to ensure we don't false-negative on case
    33     # insensitive operating systems (like Windows).
    3437    base = force_unicode(base)
    3538    paths = [force_unicode(p) for p in paths]
    36     final_path = normcase(abspathu(join(base, *paths)))
    37     base_path = normcase(abspathu(base))
     39    final_path = abspathu(join(base, *paths))
     40    fp = normcase(final_path)
     41    final_path = _normcase(final_path)
     42
     43    base_path = abspathu(base)
     44    bp = normcase(base_path)
     45    base_path = _normcase(base_path)
     46
    3847    base_path_len = len(base_path)
    3948    # Ensure final_path starts with base_path and that the next character after
    40     # the final path is os.sep (or nothing, in which case final_path must be
    41     # equal to base_path).
    42     if not final_path.startswith(base_path) \
    43        or final_path[base_path_len:base_path_len+1] not in ('', sep):
     49    # the base path portion of final_path is os.sep (or nothing, in which case
     50    # final_path must be equal to base_path).
     51    # We need to use normcase in these checks to ensure we don't false-negative
     52    # on case insensitive operating systems (like Windows).
     53    if not fp.startswith(bp) \
     54       or fp[base_path_len:base_path_len+1] not in ('', sep):
    4455        raise ValueError('the joined path is located outside of the base path'
    4556                         ' component')
    4657    return final_path
  • tests/regressiontests/file_storage/tests.py

    diff --git a/tests/regressiontests/file_storage/tests.py b/tests/regressiontests/file_storage/tests.py
    a b  
    55>>> import tempfile
    66>>> from django.core.files.storage import FileSystemStorage
    77>>> from django.core.files.base import ContentFile
     8>>> import os.path
    89
    910# Set up a unique temporary directory
    1011>>> import os
     
    4344  ...
    4445SuspiciousOperation: Attempted access to '/etc/passwd' denied.
    4546
     47# Case should be preserved by the storage backend
     48
     49# Set up a unique temporary directory with a mixed case name
     50>>> temp_dir2 = tempfile.mktemp()
     51>>> dn, bn = os.path.split(temp_dir2)
     52>>> bn = bn[0].swapcase() + bn[1:-1] + bn[-1].swapcase()
     53>>> temp_dir2 = os.path.join(dn, bn)
     54>>> os.makedirs(temp_dir2)
     55
     56>>> temp_storage2 = FileSystemStorage(location=temp_dir2)
     57
     58# Ask the storage backend to store a file with a mixed case filename
     59>>> mixed_case = 'CaSe_SeNsItIvE'
     60>>> file = temp_storage2.open(mixed_case, 'w')
     61>>> file.write('storage contents')
     62>>> file.close()
     63>>> os.path.join(temp_dir2, mixed_case) == temp_storage2.path(mixed_case)
     64True
     65>>> temp_storage2.delete(mixed_case)
     66
    4667# Custom storage systems can be created to customize behavior
    4768
    4869>>> class CustomStorage(FileSystemStorage):
     
    7091>>> custom_storage.delete(first)
    7192>>> custom_storage.delete(second)
    7293
    73 # Cleanup the temp dir
     94# Cleanup the temp dirs
    7495>>> os.rmdir(temp_dir)
     96>>> os.rmdir(temp_dir2)
    7597
    7698
    7799# Regression test for #8156: files with unicode names I can't quite figure out the
  • tests/regressiontests/file_uploads/tests.py

    diff --git a/tests/regressiontests/file_uploads/tests.py b/tests/regressiontests/file_uploads/tests.py
    a b  
    11import os
     2import os.path
    23import errno
    34import shutil
    45import unittest
     
    229230            # CustomUploadError is the error that should have been raised
    230231            self.assertEqual(err.__class__, uploadhandler.CustomUploadError)
    231232
     233    def test_filename_case_preservation(self):
     234        """
     235        The storage backend shouldn't mess with the case of the filenames
     236        uploaded.
     237        """
     238        # Synthetize the contents of a file upload with a mixed
     239        # case filename so we don't have to carry such a file
     240        # in the Django tests source code tree
     241        OUR_BOUNDARY='oUrBoUnDaRyStRiNg'
     242        post_data = [
     243                '--%s' % OUR_BOUNDARY,
     244                'Content-Disposition: form-data; name="file_field"; filename="MiXeD_cAsE.txt"',
     245                'Content-Type: application/octet-stream',
     246                '',
     247                'file contents\n'
     248                '',
     249                '--%s--\r\n' % OUR_BOUNDARY,
     250                ]
     251        response = self.client.post('/file_uploads/filename_case/', '\r\n'.join(post_data),
     252                'multipart/form-data; boundary=%s' % OUR_BOUNDARY)
     253        self.assertEqual(response.status_code, 200)
     254        id = int(response.content)
     255        obj = FileModel.objects.get(pk=id)
     256        # The name of the file uploaded and the file stored in the server-side
     257        # shouldn't differ
     258        self.assertEqual(os.path.basename(obj.testfile.path), 'MiXeD_cAsE.txt')
     259
    232260class DirectoryCreationTests(unittest.TestCase):
    233261    """
    234262    Tests for error handling during directory creation
  • tests/regressiontests/file_uploads/urls.py

    diff --git a/tests/regressiontests/file_uploads/urls.py b/tests/regressiontests/file_uploads/urls.py
    a b  
    99    (r'^quota/broken/$',    views.file_upload_quota_broken),
    1010    (r'^getlist_count/$',   views.file_upload_getlist_count),
    1111    (r'^upload_errors/$',   views.file_upload_errors),
     12    (r'^filename_case/$',   views.file_upload_filename_case_view),
    1213)
  • tests/regressiontests/file_uploads/views.py

    diff --git a/tests/regressiontests/file_uploads/views.py b/tests/regressiontests/file_uploads/views.py
    a b  
    8888def file_upload_errors(request):
    8989    request.upload_handlers.insert(0, ErroringUploadHandler())
    9090    return file_upload_echo(request)
     91
     92def file_upload_filename_case_view(request):
     93    # Adding the file to the database should succeed
     94    file = request.FILES['file_field']
     95    obj = FileModel()
     96    obj.testfile.save(file.name, file)
     97
     98    return HttpResponse('%d' % obj.pk)
     99
  • tests/regressiontests/templates/tests.py

    diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
    a b  
    137137        if os.path.normcase('/TEST') == os.path.normpath('/test'):
    138138            template_dirs = ['/dir1', '/DIR2']
    139139            test_template_sources('index.html', template_dirs,
    140                                   ['/dir1/index.html', '/dir2/index.html'])
     140                                  ['/dir1/index.html', '/DIR2/index.html'])
    141141            test_template_sources('/DIR1/index.HTML', template_dirs,
    142                                   ['/dir1/index.html'])
     142                                  ['/DIR1/index.HTML'])
    143143
    144144    def test_token_smart_split(self):
    145145        # Regression test for #7027
Back to Top