Ticket #13721: content_type_extra.3.diff

File content_type_extra.3.diff, 9.9 KB (added by mvschaik, 2 years ago)

Updated patch to apply to current master

  • django/core/files/uploadhandler.py

    diff --git a/django/core/files/uploadhandler.py b/django/core/files/uploadhandler.py
    index f5e95cf..7f8fcf6 100644
    a b class FileUploadHandler(object): 
    8484        """
    8585        pass
    8686
    87     def new_file(self, field_name, file_name, content_type, content_length, charset=None):
     87    def new_file(self, field_name, file_name, content_type, content_length,
     88            charset=None, content_type_extra=None):
    8889        """
    8990        Signal that a new file has been started.
    9091
    class FileUploadHandler(object): 
    9697        self.content_type = content_type
    9798        self.content_length = content_length
    9899        self.charset = charset
     100        if content_type_extra is None:
     101            content_type_extra = {}
     102        self.content_type_extra = content_type_extra
    99103
    100104    def receive_data_chunk(self, raw_data, start):
    101105        """
  • django/http/multipartparser.py

    diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py
    index 070874f..2199c8e 100644
    a b class MultiPartParser(object): 
    176176                    file_name = self.IE_sanitize(unescape_entities(file_name))
    177177
    178178                    content_type = meta_data.get('content-type', ('',))[0].strip()
     179                    content_type_extra = meta_data.get('content-type', (0, {}))[1]
     180                    if content_type_extra is None:
     181                        content_type_extra = {}
    179182                    try:
    180                         charset = meta_data.get('content-type', (0, {}))[1].get('charset', None)
     183                        charset = content_type_extra.get('charset', None)
    181184                    except:
    182185                        charset = None
    183186
    class MultiPartParser(object): 
    192195                            try:
    193196                                handler.new_file(field_name, file_name,
    194197                                                 content_type, content_length,
    195                                                  charset)
     198                                                 charset, content_type_extra.copy())
    196199                            except StopFutureHandlers:
    197200                                break
    198201
  • django/test/client.py

    diff --git a/django/test/client.py b/django/test/client.py
    index 2506437..f432abc 100644
    a b def encode_multipart(boundary, data): 
    178178
    179179def encode_file(boundary, key, file):
    180180    to_bytes = lambda s: force_bytes(s, settings.DEFAULT_CHARSET)
    181     content_type = mimetypes.guess_type(file.name)[0]
     181    if hasattr(file, 'content_type'):
     182        content_type = file.content_type
     183    else:
     184        content_type = mimetypes.guess_type(file.name)[0]
    182185    if content_type is None:
    183186        content_type = 'application/octet-stream'
    184187    return [
  • docs/topics/http/file-uploads.txt

    diff --git a/docs/topics/http/file-uploads.txt b/docs/topics/http/file-uploads.txt
    index 80bd5f3..142031c 100644
    a b In addition to those inherited from :class:`~django.core.files.File`, all 
    243243    For :mimetype:`text/*` content-types, the character set (i.e. ``utf8``)
    244244    supplied by the browser. Again, "trust but verify" is the best policy here.
    245245
     246.. attribute:: UploadedFile.content_type_extra
     247
     248    A dict containing the extra parameters that were passed to the
     249    content-type header.
     250
    246251.. attribute:: UploadedFile.temporary_file_path()
    247252
    248253    Only files uploaded onto disk will have this method; it returns the full
    attributes: 
    402407
    403408    The default is 64*2\ :sup:`10` bytes, or 64 KB.
    404409
    405 ``FileUploadHandler.new_file(self, field_name, file_name, content_type, content_length, charset)``
     410``FileUploadHandler.new_file(self, field_name, file_name, content_type, content_length, charset, content_type_extra)``
    406411    Callback signaling that a new file upload is starting. This is called
    407412    before any data has been fed to any upload handlers.
    408413
    attributes: 
    419424    ``charset`` is the character set (i.e. ``utf8``) given by the browser.
    420425    Like ``content_length``, this sometimes won't be provided.
    421426
     427    ``content_type_extra`` is a dict containing the extra parameters that
     428    were passed to the content-type header.
     429
    422430    This method may raise a ``StopFutureHandlers`` exception to prevent
    423431    future handlers from handling this file.
    424432
  • tests/regressiontests/file_uploads/tests.py

    diff --git a/tests/regressiontests/file_uploads/tests.py b/tests/regressiontests/file_uploads/tests.py
    index 45e7342..2f5f363 100644
    a b class FileUploadTests(TestCase): 
    249249        got = json.loads(response.content.decode('utf-8'))
    250250        self.assertTrue('f' not in got)
    251251
     252    def test_extra_content_type(self):
     253        f = tempfile.NamedTemporaryFile()
     254        f.write('a' * (2 ** 21))
     255        f.seek(0)
     256        f.content_type = 'text/plain; blob-key=upload blob key; other=test'
     257
     258        response = self.client.post("/file_uploads/content_type_extra/", {'f': f})
     259        got = json.loads(response.content)
     260        self.assertEqual(got['f'], 'upload blob key')
     261
    252262    def test_broken_custom_upload_handler(self):
    253263        f = tempfile.NamedTemporaryFile()
    254264        f.write(b'a' * (2 ** 21))
  • tests/regressiontests/file_uploads/uploadhandler.py

    diff --git a/tests/regressiontests/file_uploads/uploadhandler.py b/tests/regressiontests/file_uploads/uploadhandler.py
    index b30ef13..a079aff 100644
    a b  
    22Upload handlers to test the upload API.
    33"""
    44
    5 from django.core.files.uploadhandler import FileUploadHandler, StopUpload
     5from django.core.files.uploadedfile import InMemoryUploadedFile
     6from django.core.files.uploadhandler import (FileUploadHandler, StopUpload,
     7                                             StopFutureHandlers)
     8from StringIO import StringIO
    69
    710
    811class QuotaUploadHandler(FileUploadHandler):
    class ErroringUploadHandler(FileUploadHandler): 
    3336    """A handler that raises an exception."""
    3437    def receive_data_chunk(self, raw_data, start):
    3538        raise CustomUploadError("Oops!")
     39
     40class ContentTypeExtraUploadHandler(FileUploadHandler):
     41    """
     42    File upload handler that handles content_type_extra
     43    """
     44
     45    def new_file(self, *args, **kwargs):
     46        super(ContentTypeExtraUploadHandler, self).new_file(*args, **kwargs)
     47        self.blobkey = self.content_type_extra.get('blob-key', '')
     48        self.file = StringIO()
     49        self.file.write(self.blobkey)
     50        self.active = self.blobkey is not None
     51        if self.active:
     52            raise StopFutureHandlers()
     53
     54    def receive_data_chunk(self, raw_data, start):
     55        """
     56        Add the data to the StringIO file.
     57        """
     58        if not self.active:
     59            return raw_data
     60
     61    def file_complete(self, file_size):
     62        if not self.active:
     63            return
     64
     65        self.file.seek(0)
     66        return InMemoryUploadedFile(
     67            file = self.file,
     68            field_name = self.field_name,
     69            name = self.file_name,
     70            content_type = self.content_type,
     71            size = file_size,
     72            charset = self.charset
     73        )
  • tests/regressiontests/file_uploads/urls.py

    diff --git a/tests/regressiontests/file_uploads/urls.py b/tests/regressiontests/file_uploads/urls.py
    index fc55768..405c727 100644
    a b from . import views 
    66
    77
    88urlpatterns = patterns('',
    9     (r'^upload/$',          views.file_upload_view),
    10     (r'^verify/$',          views.file_upload_view_verify),
    11     (r'^unicode_name/$',    views.file_upload_unicode_name),
    12     (r'^echo/$',            views.file_upload_echo),
    13     (r'^echo_content/$',    views.file_upload_echo_content),
    14     (r'^quota/$',           views.file_upload_quota),
    15     (r'^quota/broken/$',    views.file_upload_quota_broken),
    16     (r'^getlist_count/$',   views.file_upload_getlist_count),
    17     (r'^upload_errors/$',   views.file_upload_errors),
    18     (r'^filename_case/$',   views.file_upload_filename_case_view),
     9    (r'^upload/$',              views.file_upload_view),
     10    (r'^verify/$',              views.file_upload_view_verify),
     11    (r'^unicode_name/$',        views.file_upload_unicode_name),
     12    (r'^echo/$',                views.file_upload_echo),
     13    (r'^echo_content/$',        views.file_upload_echo_content),
     14    (r'^quota/$',               views.file_upload_quota),
     15    (r'^quota/broken/$',        views.file_upload_quota_broken),
     16    (r'^getlist_count/$',       views.file_upload_getlist_count),
     17    (r'^upload_errors/$',       views.file_upload_errors),
     18    (r'^content_type_extra/$',  views.file_upload_content_type_extra),
     19    (r'^filename_case/$',       views.file_upload_filename_case_view),
    1920)
  • tests/regressiontests/file_uploads/views.py

    diff --git a/tests/regressiontests/file_uploads/views.py b/tests/regressiontests/file_uploads/views.py
    index eb7b654..8275365 100644
    a b from django.utils.encoding import force_bytes 
    1111
    1212from .models import FileModel
    1313from .tests import UNICODE_FILENAME, UPLOAD_TO
    14 from .uploadhandler import QuotaUploadHandler, ErroringUploadHandler
     14from .uploadhandler import (QuotaUploadHandler, ErroringUploadHandler,
     15                            ContentTypeExtraUploadHandler)
    1516
    1617
    1718def file_upload_view(request):
    def file_upload_getlist_count(request): 
    124125        file_counts[key] = len(request.FILES.getlist(key))
    125126    return HttpResponse(json.dumps(file_counts))
    126127
     128def file_upload_content_type_extra(request):
     129    request.upload_handlers.insert(0, ContentTypeExtraUploadHandler())
     130    r = dict([(k, f.read()) for k, f in request.FILES.items()])
     131    return HttpResponse(json.dumps(r))
     132
    127133def file_upload_errors(request):
    128134    request.upload_handlers.insert(0, ErroringUploadHandler())
    129135    return file_upload_echo(request)
Back to Top