Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #7658 -- Added some Windows-specific tempfile handling. The sta…

…ndard

stuff doesn't work with the way Django's file uploading code wants to operate.
Patch from Mike Axiak.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@8096 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 103d484807050c00d02641aa04670cea8d0e68a4 1 parent e29aece
Malcolm Tredinnick authored July 26, 2008
58  django/core/files/temp.py
... ...
@@ -0,0 +1,58 @@
  1
+"""
  2
+The temp module provides a NamedTemporaryFile that can be re-opened on any
  3
+platform. Most platforms use the standard Python tempfile.TemporaryFile class,
  4
+but MS Windows users are given a custom class.
  5
+
  6
+This is needed because in Windows NT, the default implementation of
  7
+NamedTemporaryFile uses the O_TEMPORARY flag, and thus cannot be reopened [1].
  8
+
  9
+1: http://mail.python.org/pipermail/python-list/2005-December/359474.html
  10
+"""
  11
+
  12
+import os
  13
+import tempfile
  14
+
  15
+__all__ = ('NamedTemporaryFile', 'gettempdir',)
  16
+
  17
+if os.name == 'nt':
  18
+    class TemporaryFile(object):
  19
+        """
  20
+        Temporary file object constructor that works in Windows and supports
  21
+        reopening of the temporary file in windows.
  22
+        """
  23
+        def __init__(self, mode='w+b', bufsize=-1, suffix='', prefix='',
  24
+                dir=None):
  25
+            fd, name = tempfile.mkstemp(suffix=suffix, prefix=prefix,
  26
+                                          dir=dir)
  27
+            self.name = name
  28
+            self._file = os.fdopen(fd, mode, bufsize)
  29
+
  30
+        def __del__(self):
  31
+            try:
  32
+                self._file.close()
  33
+            except (OSError, IOError):
  34
+                pass
  35
+            try:
  36
+                os.unlink(self.name)
  37
+            except (OSError):
  38
+                pass
  39
+
  40
+            try:
  41
+                super(TemporaryFile, self).__del__()
  42
+            except AttributeError:
  43
+                pass
  44
+
  45
+
  46
+        def read(self, *args):          return self._file.read(*args)
  47
+        def seek(self, offset):         return self._file.seek(offset)
  48
+        def write(self, s):             return self._file.write(s)
  49
+        def close(self):                return self._file.close()
  50
+        def __iter__(self):             return iter(self._file)
  51
+        def readlines(self, size=None): return self._file.readlines(size)
  52
+        def xreadlines(self):           return self._file.xreadlines()
  53
+
  54
+    NamedTemporaryFile = TemporaryFile
  55
+else:
  56
+    NamedTemporaryFile = tempfile.NamedTemporaryFile
  57
+
  58
+gettempdir = tempfile.gettempdir
3  django/core/files/uploadedfile.py
@@ -3,7 +3,6 @@
3 3
 """
4 4
 
5 5
 import os
6  
-import tempfile
7 6
 import warnings
8 7
 try:
9 8
     from cStringIO import StringIO
@@ -12,6 +11,8 @@
12 11
 
13 12
 from django.conf import settings
14 13
 
  14
+from django.core.files import temp as tempfile
  15
+
15 16
 __all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile', 'SimpleUploadedFile')
16 17
 
17 18
 # Because we fooled around with it a bunch, UploadedFile has a bunch
28  tests/regressiontests/file_uploads/tests.py
@@ -2,9 +2,9 @@
2 2
 import errno
3 3
 import sha
4 4
 import shutil
5  
-import tempfile
6 5
 import unittest
7 6
 
  7
+from django.core.files import temp as tempfile
8 8
 from django.core.files.uploadedfile import SimpleUploadedFile
9 9
 from django.test import TestCase, client
10 10
 from django.utils import simplejson
@@ -22,7 +22,7 @@ def test_simple_upload(self):
22 22
 
23 23
     def test_large_upload(self):
24 24
         tdir = tempfile.gettempdir()
25  
-        
  25
+
26 26
         file1 = tempfile.NamedTemporaryFile(suffix=".file1", dir=tdir)
27 27
         file1.write('a' * (2 ** 21))
28 28
         file1.seek(0)
@@ -58,11 +58,11 @@ def test_large_upload(self):
58 58
             pass
59 59
 
60 60
         self.assertEqual(response.status_code, 200)
61  
-    
  61
+
62 62
     def test_dangerous_file_names(self):
63 63
         """Uploaded file names should be sanitized before ever reaching the view."""
64 64
         # This test simulates possible directory traversal attacks by a
65  
-        # malicious uploader We have to do some monkeybusiness here to construct 
  65
+        # malicious uploader We have to do some monkeybusiness here to construct
66 66
         # a malicious payload with an invalid file name (containing os.sep or
67 67
         # os.pardir). This similar to what an attacker would need to do when
68 68
         # trying such an attack.
@@ -79,7 +79,7 @@ def test_dangerous_file_names(self):
79 79
             "..\\..\\hax0rd.txt",       # Relative path, win-style.
80 80
             "../..\\hax0rd.txt"         # Relative path, mixed.
81 81
         ]
82  
-        
  82
+
83 83
         payload = []
84 84
         for i, name in enumerate(scary_file_names):
85 85
             payload.extend([
@@ -93,7 +93,7 @@ def test_dangerous_file_names(self):
93 93
             '--' + client.BOUNDARY + '--',
94 94
             '',
95 95
         ])
96  
-        
  96
+
97 97
         payload = "\r\n".join(payload)
98 98
         r = {
99 99
             'CONTENT_LENGTH': len(payload),
@@ -109,7 +109,7 @@ def test_dangerous_file_names(self):
109 109
         for i, name in enumerate(scary_file_names):
110 110
             got = recieved["file%s" % i]
111 111
             self.assertEqual(got, "hax0rd.txt")
112  
-            
  112
+
113 113
     def test_filename_overflow(self):
114 114
         """File names over 256 characters (dangerous on some platforms) get fixed up."""
115 115
         name = "%s.txt" % ("f"*500)
@@ -131,26 +131,26 @@ def test_filename_overflow(self):
131 131
         }
132 132
         got = simplejson.loads(self.client.request(**r).content)
133 133
         self.assert_(len(got['file']) < 256, "Got a long file name (%s characters)." % len(got['file']))
134  
-        
  134
+
135 135
     def test_custom_upload_handler(self):
136  
-        # A small file (under the 5M quota)                
  136
+        # A small file (under the 5M quota)
137 137
         smallfile = tempfile.NamedTemporaryFile()
138 138
         smallfile.write('a' * (2 ** 21))
139 139
 
140 140
         # A big file (over the quota)
141 141
         bigfile = tempfile.NamedTemporaryFile()
142 142
         bigfile.write('a' * (10 * 2 ** 20))
143  
-                
  143
+
144 144
         # Small file posting should work.
145 145
         response = self.client.post('/file_uploads/quota/', {'f': open(smallfile.name)})
146 146
         got = simplejson.loads(response.content)
147 147
         self.assert_('f' in got)
148  
-        
  148
+
149 149
         # Large files don't go through.
150 150
         response = self.client.post("/file_uploads/quota/", {'f': open(bigfile.name)})
151 151
         got = simplejson.loads(response.content)
152 152
         self.assert_('f' not in got)
153  
-        
  153
+
154 154
     def test_broken_custom_upload_handler(self):
155 155
         f = tempfile.NamedTemporaryFile()
156 156
         f.write('a' * (2 ** 21))
@@ -189,7 +189,7 @@ def test_fileupload_getlist(self):
189 189
 
190 190
 class DirectoryCreationTests(unittest.TestCase):
191 191
     """
192  
-    Tests for error handling during directory creation 
  192
+    Tests for error handling during directory creation
193 193
     via _save_FIELD_file (ticket #6450)
194 194
     """
195 195
     def setUp(self):
@@ -221,7 +221,7 @@ def test_not_a_directory(self):
221 221
         except IOError, err:
222 222
             # The test needs to be done on a specific string as IOError
223 223
             # is raised even without the patch (just not early enough)
224  
-            self.assertEquals(err.args[0], 
  224
+            self.assertEquals(err.args[0],
225 225
                               "%s exists and is not a directory" % UPLOAD_TO)
226 226
         except:
227 227
             self.fail("IOError not raised")

0 notes on commit 103d484

Please sign in to comment.
Something went wrong with that request. Please try again.