Code

Ticket #13721: content_type_extra.2.diff

File content_type_extra.2.diff, 9.3 KB (added by wkornewald, 3 years ago)

patch against trunk

Line 
1diff -r 6f0361df1c82 django/core/files/uploadhandler.py
2--- a/django/core/files/uploadhandler.py        Fri May 20 02:42:28 2011 +0000
3+++ b/django/core/files/uploadhandler.py        Fri May 20 08:53:10 2011 +0200
4@@ -84,7 +84,8 @@
5         """
6         pass
7 
8-    def new_file(self, field_name, file_name, content_type, content_length, charset=None):
9+    def new_file(self, field_name, file_name, content_type, content_length,
10+            charset=None, content_type_extra=None):
11         """
12         Signal that a new file has been started.
13 
14@@ -96,6 +97,9 @@
15         self.content_type = content_type
16         self.content_length = content_length
17         self.charset = charset
18+        if content_type_extra is None:
19+            content_type_extra = {}
20+        self.content_type_extra = content_type_extra
21 
22     def receive_data_chunk(self, raw_data, start):
23         """
24diff -r 6f0361df1c82 django/http/multipartparser.py
25--- a/django/http/multipartparser.py    Fri May 20 02:42:28 2011 +0000
26+++ b/django/http/multipartparser.py    Fri May 20 08:53:10 2011 +0200
27@@ -171,8 +171,11 @@
28                     file_name = self.IE_sanitize(unescape_entities(file_name))
29 
30                     content_type = meta_data.get('content-type', ('',))[0].strip()
31+                    content_type_extra = meta_data.get('content-type', (0,{}))[1]
32+                    if content_type_extra is None:
33+                        content_type_extra = {}
34                     try:
35-                        charset = meta_data.get('content-type', (0,{}))[1].get('charset', None)
36+                        charset = content_type_extra.get('charset', None)
37                     except:
38                         charset = None
39 
40@@ -187,7 +190,7 @@
41                             try:
42                                 handler.new_file(field_name, file_name,
43                                                  content_type, content_length,
44-                                                 charset)
45+                                                 charset, content_type_extra.copy())
46                             except StopFutureHandlers:
47                                 break
48 
49diff -r 6f0361df1c82 django/test/client.py
50--- a/django/test/client.py     Fri May 20 02:42:28 2011 +0000
51+++ b/django/test/client.py     Fri May 20 08:53:10 2011 +0200
52@@ -146,7 +146,10 @@
53 
54 def encode_file(boundary, key, file):
55     to_str = lambda s: smart_str(s, settings.DEFAULT_CHARSET)
56-    content_type = mimetypes.guess_type(file.name)[0]
57+    if hasattr(file, 'content_type'):
58+        content_type = file.content_type
59+    else:
60+        content_type = mimetypes.guess_type(file.name)[0]
61     if content_type is None:
62         content_type = 'application/octet-stream'
63     return [
64diff -r 6f0361df1c82 docs/topics/http/file-uploads.txt
65--- a/docs/topics/http/file-uploads.txt Fri May 20 02:42:28 2011 +0000
66+++ b/docs/topics/http/file-uploads.txt Fri May 20 08:53:10 2011 +0200
67@@ -200,6 +200,11 @@
68     For ``text/*`` content-types, the character set (i.e. ``utf8``) supplied
69     by the browser. Again, "trust but verify" is the best policy here.
70 
71+.. attribute:: UploadedFile.content_type_extra
72+
73+    A dict containing the extra parameters that were passed to the
74+    content-type header.
75+
76 .. attribute:: UploadedFile.temporary_file_path()
77 
78     Only files uploaded onto disk will have this method; it returns the full
79@@ -357,7 +362,7 @@
80 
81         The default is 64*2\ :sup:`10` bytes, or 64 KB.
82 
83-    ``FileUploadHandler.new_file(self, field_name, file_name, content_type, content_length, charset)``
84+    ``FileUploadHandler.new_file(self, field_name, file_name, content_type, content_length, charset, content_type_extra)``
85         Callback signaling that a new file upload is starting. This is called
86         before any data has been fed to any upload handlers.
87 
88@@ -374,6 +379,9 @@
89         ``charset`` is the character set (i.e. ``utf8``) given by the browser.
90         Like ``content_length``, this sometimes won't be provided.
91 
92+        ``content_type_extra`` is a dict containing the extra parameters that
93+        were passed to the content-type header.
94+
95         This method may raise a ``StopFutureHandlers`` exception to prevent
96         future handlers from handling this file.
97 
98diff -r 6f0361df1c82 tests/regressiontests/file_uploads/tests.py
99--- a/tests/regressiontests/file_uploads/tests.py       Fri May 20 02:42:28 2011 +0000
100+++ b/tests/regressiontests/file_uploads/tests.py       Fri May 20 08:53:10 2011 +0200
101@@ -197,6 +197,16 @@
102         got = simplejson.loads(response.content)
103         self.assertTrue('f' not in got)
104 
105+    def test_extra_content_type(self):
106+        f = tempfile.NamedTemporaryFile()
107+        f.write('a' * (2 ** 21))
108+        f.seek(0)
109+        f.content_type = 'text/plain; blob-key=upload blob key; other=test'
110+
111+        response = self.client.post("/file_uploads/content_type_extra/", {'f': f})
112+        got = simplejson.loads(response.content)
113+        self.assertEqual(got['f'], 'upload blob key')
114+
115     def test_broken_custom_upload_handler(self):
116         f = tempfile.NamedTemporaryFile()
117         f.write('a' * (2 ** 21))
118diff -r 6f0361df1c82 tests/regressiontests/file_uploads/uploadhandler.py
119--- a/tests/regressiontests/file_uploads/uploadhandler.py       Fri May 20 02:42:28 2011 +0000
120+++ b/tests/regressiontests/file_uploads/uploadhandler.py       Fri May 20 08:53:10 2011 +0200
121@@ -2,7 +2,10 @@
122 Upload handlers to test the upload API.
123 """
124 
125-from django.core.files.uploadhandler import FileUploadHandler, StopUpload
126+from django.core.files.uploadedfile import InMemoryUploadedFile
127+from django.core.files.uploadhandler import (FileUploadHandler, StopUpload,
128+    StopFutureHandlers)
129+from StringIO import StringIO
130 
131 class QuotaUploadHandler(FileUploadHandler):
132     """
133@@ -32,3 +35,38 @@
134     """A handler that raises an exception."""
135     def receive_data_chunk(self, raw_data, start):
136         raise CustomUploadError("Oops!")
137+
138+class ContentTypeExtraUploadHandler(FileUploadHandler):
139+    """
140+    File upload handler that handles content_type_extra
141+    """
142+
143+    def new_file(self, *args, **kwargs):
144+        super(ContentTypeExtraUploadHandler, self).new_file(*args, **kwargs)
145+        self.blobkey = self.content_type_extra.get('blob-key', '')
146+        self.file = StringIO()
147+        self.file.write(self.blobkey)
148+        self.active = self.blobkey is not None
149+        if self.active:
150+            raise StopFutureHandlers()
151+
152+    def receive_data_chunk(self, raw_data, start):
153+        """
154+        Add the data to the StringIO file.
155+        """
156+        if not self.active:
157+            return raw_data
158+
159+    def file_complete(self, file_size):
160+        if not self.active:
161+            return
162+
163+        self.file.seek(0)
164+        return InMemoryUploadedFile(
165+            file = self.file,
166+            field_name = self.field_name,
167+            name = self.file_name,
168+            content_type = self.content_type,
169+            size = file_size,
170+            charset = self.charset
171+        )
172diff -r 6f0361df1c82 tests/regressiontests/file_uploads/urls.py
173--- a/tests/regressiontests/file_uploads/urls.py        Fri May 20 02:42:28 2011 +0000
174+++ b/tests/regressiontests/file_uploads/urls.py        Fri May 20 08:53:10 2011 +0200
175@@ -2,13 +2,14 @@
176 import views
177 
178 urlpatterns = patterns('',
179-    (r'^upload/$',          views.file_upload_view),
180-    (r'^verify/$',          views.file_upload_view_verify),
181-    (r'^unicode_name/$',    views.file_upload_unicode_name),
182-    (r'^echo/$',            views.file_upload_echo),
183-    (r'^echo_content/$',    views.file_upload_echo_content),
184-    (r'^quota/$',           views.file_upload_quota),
185-    (r'^quota/broken/$',    views.file_upload_quota_broken),
186-    (r'^getlist_count/$',   views.file_upload_getlist_count),
187-    (r'^upload_errors/$',   views.file_upload_errors),
188+    (r'^upload/$',              views.file_upload_view),
189+    (r'^verify/$',              views.file_upload_view_verify),
190+    (r'^unicode_name/$',        views.file_upload_unicode_name),
191+    (r'^echo/$',                views.file_upload_echo),
192+    (r'^echo_content/$',        views.file_upload_echo_content),
193+    (r'^quota/$',               views.file_upload_quota),
194+    (r'^quota/broken/$',        views.file_upload_quota_broken),
195+    (r'^getlist_count/$',       views.file_upload_getlist_count),
196+    (r'^upload_errors/$',       views.file_upload_errors),
197+    (r'^content_type_extra/$',  views.file_upload_content_type_extra),
198 )
199diff -r 6f0361df1c82 tests/regressiontests/file_uploads/views.py
200--- a/tests/regressiontests/file_uploads/views.py       Fri May 20 02:42:28 2011 +0000
201+++ b/tests/regressiontests/file_uploads/views.py       Fri May 20 08:53:10 2011 +0200
202@@ -4,7 +4,8 @@
203 from django.http import HttpResponse, HttpResponseServerError
204 from django.utils import simplejson
205 from models import FileModel, UPLOAD_TO
206-from uploadhandler import QuotaUploadHandler, ErroringUploadHandler
207+from uploadhandler import (QuotaUploadHandler, ErroringUploadHandler,
208+    ContentTypeExtraUploadHandler)
209 from tests import UNICODE_FILENAME
210 
211 def file_upload_view(request):
212@@ -120,3 +121,8 @@
213 def file_upload_errors(request):
214     request.upload_handlers.insert(0, ErroringUploadHandler())
215     return file_upload_echo(request)
216+
217+def file_upload_content_type_extra(request):
218+    request.upload_handlers.insert(0, ContentTypeExtraUploadHandler())
219+    r = dict([(k, f.read()) for k, f in request.FILES.items()])
220+    return HttpResponse(simplejson.dumps(r))