diff --git a/django/core/files/uploadedfile.py b/django/core/files/uploadedfile.py
index 39b99ff..c253062 100644
a
|
b
|
|
2 | 2 | Classes representing uploaded files. |
3 | 3 | """ |
4 | 4 | |
5 | | import os |
| 5 | import ntpath |
6 | 6 | from io import BytesIO |
7 | 7 | |
8 | 8 | from django.conf import settings |
… |
… |
class UploadedFile(File):
|
39 | 39 | def _set_name(self, name): |
40 | 40 | # Sanitize the file name so that it can't be dangerous. |
41 | 41 | if name is not None: |
| 42 | # If name ends in backslash replace with 0 |
| 43 | if name[-1] != "\\": |
| 44 | name = os.path.basename(name) |
42 | 45 | # Just use the basename of the file -- anything else is dangerous. |
43 | | name = os.path.basename(name) |
| 46 | name = ntpath.basename(name) |
44 | 47 | |
45 | 48 | # File names longer than 255 characters can cause problems on older OSes. |
46 | 49 | if len(name) > 255: |
47 | | name, ext = os.path.splitext(name) |
| 50 | name, ext = ntpath.splitext(name) |
48 | 51 | name = name[:255 - len(ext)] + ext |
49 | 52 | |
50 | 53 | self._name = name |
diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py
index 070874f..d84c3e0 100644
a
|
b
|
class MultiPartParser(object):
|
173 | 173 | if not file_name: |
174 | 174 | continue |
175 | 175 | file_name = force_text(file_name, encoding, errors='replace') |
176 | | file_name = self.IE_sanitize(unescape_entities(file_name)) |
| 176 | file_name = unescape_entities(file_name) |
177 | 177 | |
178 | 178 | content_type = meta_data.get('content-type', ('',))[0].strip() |
179 | 179 | try: |
… |
… |
class MultiPartParser(object):
|
258 | 258 | file_obj) |
259 | 259 | break |
260 | 260 | |
261 | | def IE_sanitize(self, filename): |
262 | | """Cleanup filename from Internet Explorer full paths.""" |
263 | | return filename and filename[filename.rfind("\\")+1:].strip() |
264 | | |
265 | 261 | class LazyStream(six.Iterator): |
266 | 262 | """ |
267 | 263 | The LazyStream wrapper allows one to get and "unget" bytes from a stream. |
diff --git a/tests/regressiontests/file_uploads/tests.py b/tests/regressiontests/file_uploads/tests.py
index 45e7342..d8292ff 100644
a
|
b
|
class FileUploadTests(TestCase):
|
362 | 362 | # shouldn't differ. |
363 | 363 | self.assertEqual(os.path.basename(obj.testfile.path), 'MiXeD_cAsE.txt') |
364 | 364 | |
| 365 | def test_fail_backslash(self): |
| 366 | """ |
| 367 | Tests filename ending with a backslash, issue #18150 reports crashes |
| 368 | when a filename ends with a backslash |
| 369 | """ |
| 370 | name_backslash = "backslash.jpg\\" |
| 371 | payload = client.FakePayload() |
| 372 | payload.write('\r\n'.join([ |
| 373 | '--' + client.BOUNDARY, |
| 374 | 'Content-Disposition: form-data; name="file1"; filename="%s"' % name_backslash, |
| 375 | 'Content-Type: application/octet-stream', |
| 376 | '', |
| 377 | '' |
| 378 | ])) |
| 379 | payload.write('\r\n--' + client.BOUNDARY + '--\r\n') |
| 380 | |
| 381 | r = { |
| 382 | 'CONTENT_LENGTH': len(payload), |
| 383 | 'CONTENT_TYPE': client.MULTIPART_CONTENT, |
| 384 | 'PATH_INFO': "/file_uploads/echo/", |
| 385 | 'REQUEST_METHOD': 'POST', |
| 386 | 'wsgi.input': payload, |
| 387 | } |
| 388 | response = self.client.request(**r) |
| 389 | self.assertEqual(response.status_code, 200) |
| 390 | |
365 | 391 | @override_settings(MEDIA_ROOT=MEDIA_ROOT) |
366 | 392 | class DirectoryCreationTests(TestCase): |
367 | 393 | """ |