Ticket #20034: 1148.diff

File 1148.diff, 7.7 KB (added by tadeck, 2 years ago)

DIFF file for ticket #20034

  • AUTHORS

    diff --git a/AUTHORS b/AUTHORS
    index 4a9981d..2f91c08 100644
    a b answer newbie questions, and generally made Django that much better: 
    293293    Baurzhan Ismagulov <ibr@radix50.net>
    294294    Stephan Jaekel <steph@rdev.info>
    295295    james_027@yahoo.com
     296    Tom Jaskowski <tadeck@gmail.com>
    296297    jcrasta@gmail.com
    297298    jdetaeye
    298299    Dmitry Jemerov <intelliyole@gmail.com>
  • django/core/files/uploadhandler.py

    diff --git a/django/core/files/uploadhandler.py b/django/core/files/uploadhandler.py
    index f5e95cf..49ed98d 100644
    a b def file_complete(self, file_size): 
    113113        """
    114114        raise NotImplementedError()
    115115
     116    def variable_complete(self, variable_name, variable_value):
     117        """
     118        Signal that a new variable has been parsed from the multipart request.
     119
     120        :param variable_name: name of the variable
     121        :param variable_value: value of the multipart variable
     122        """
     123        pass
     124
    116125    def upload_complete(self):
    117126        """
    118127        Signal that the upload is complete. Subclasses should perform cleanup
  • django/http/multipartparser.py

    diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py
    index 26e10da..6679899 100644
    a b def parse(self): 
    167167                    else:
    168168                        data = field_stream.read()
    169169
    170                     self._post.appendlist(field_name,
    171                                           force_text(data, encoding, errors='replace'))
     170                    field_text = force_text(data, encoding, errors='replace')
     171                    self._post.appendlist(field_name, field_text)
     172                   
     173                    for handler in handlers:
     174                        try:
     175                            handler.variable_complete(field_name, field_text)
     176                        except StopFutureHandlers:
     177                            break
     178
    172179                elif item_type == FILE:
    173180                    # This is a file, use the handler...
    174181                    file_name = disposition.get('filename')
  • docs/topics/http/file-uploads.txt

    diff --git a/docs/topics/http/file-uploads.txt b/docs/topics/http/file-uploads.txt
    index 80bd5f3..aa857af 100644
    a b attributes: 
    425425``FileUploadHandler.upload_complete(self)``
    426426    Callback signaling that the entire upload (all files) has completed.
    427427
     428``FileUploadHandler.variable_complete(self, variable_name, variable_value)``
     429    Callback signaling that a new variable has been parsed. This is called
     430    before new file is parsed.
     431
     432    ``variable_name`` is a string name of the non-file ``<input>`` field.
     433
     434    ``variable_value`` is the value (text) provided in the field by browser.
     435
     436    This method may raise a ``StopFutureHandlers`` exception to prevent
     437    future handlers from handling this variable.
     438
     439.. versionadded:: 1.6
     440
     441    The ``variable_complete`` method was added in Django 1.6.
     442
    428443``FileUploadHandler.handle_raw_input(self, input_data, META, content_length, boundary, encoding)``
    429444    Allows the handler to completely override the parsing of the raw
    430445    HTTP input.
  • tests/requests/tests.py

    diff --git a/tests/requests/tests.py b/tests/requests/tests.py
    index 676cd05..8e76832 100644
    a b  
    11# -*- encoding: utf-8 -*-
    22from __future__ import unicode_literals
    33
     4from contextlib import contextmanager
    45import time
    56import warnings
    67from datetime import datetime, timedelta
    def read(self, len=0): 
    659660        with self.assertRaises(UnreadablePostError):
    660661            request.body
    661662
     663    def test_POST_new_variable_signal_in_multipart(self):
     664        """
     665        Multi part POST requests should allow reading variables even before
     666        parsing whole files. This can be done by overloading file upload
     667        handlers' ``new_variable`` method.
     668        """
     669        collected_variables_memory_handler = []
     670        collected_variables_temporary_handler = []
     671
     672        def get_var_collector(handler):
     673            """Retrieve variable collector for specific handler"""
     674            def _collect_variable(self, variable_name, variable_value):
     675                """Store variable in external list, to check it later"""
     676                if handler == 'memory':
     677                    collected_variables_memory_handler.append(
     678                        (variable_name, variable_value),
     679                    )
     680                elif handler == 'temporary':
     681                    collected_variables_temporary_handler.append(
     682                        (variable_name, variable_value),
     683                    )
     684                else:
     685                    raise NotImplementedError(
     686                        'Collector for %s not implemented' % (handler,),
     687                    )
     688            return _collect_variable
     689
     690        @contextmanager
     691        def override_upload_handler_methods():
     692            """Override parser method temporarily"""
     693            from django.core.files.uploadhandler import (
     694                MemoryFileUploadHandler, TemporaryFileUploadHandler,
     695            )
     696            old_method_memory = MemoryFileUploadHandler.variable_complete
     697            old_method_temporary = TemporaryFileUploadHandler.variable_complete
     698
     699            # Override handler method:
     700            MemoryFileUploadHandler.variable_complete = get_var_collector(
     701                'memory',
     702            )
     703            TemporaryFileUploadHandler.variable_complete = get_var_collector(
     704                'temporary',
     705            )
     706            yield
     707            # Recover previous state:
     708            MemoryFileUploadHandler.new_variable = old_method_memory
     709            TemporaryFileUploadHandler.new_variable = old_method_temporary
     710
     711        payload = FakePayload(
     712            "\r\n".join([
     713                '--boundary',
     714                'Content-Disposition: form-data; name="n1"',
     715                '',
     716                'value',
     717                '--boundary',
     718                'Content-Disposition: form-data; name="n2"; filename="f.txt"',
     719                'Content-Type: text/plain',
     720                '',
     721                '... contents of file1.txt ...',
     722                'value',
     723                '--boundary--',
     724                'Content-Disposition: form-data; name="n3"',
     725                '',
     726                'value',
     727                '--boundary--',
     728                '']))
     729        request = WSGIRequest({
     730            'REQUEST_METHOD': 'POST',
     731            'CONTENT_TYPE': 'multipart/form-data; boundary=boundary',
     732            'CONTENT_LENGTH': len(payload),
     733            'wsgi.input': payload})
     734
     735        # Use specific upload handlers
     736        upload_handlers = (
     737            'django.core.files.uploadhandler.MemoryFileUploadHandler',
     738            'django.core.files.uploadhandler.TemporaryFileUploadHandler',
     739        )
     740        with override_upload_handler_methods(), self.settings(
     741                FILE_UPLOAD_HANDLERS=upload_handlers,
     742        ):
     743            self.assertEqual(
     744                request.POST,
     745                {
     746                    'n1': ['value'],
     747                    'n3': ['value'],
     748                },
     749            )
     750            self.assertEqual(len(request.FILES), 1)
     751            self.assertIn('n2', request.FILES)
     752
     753            # Confirm the variables have been collected:
     754            self.assertEqual(
     755                collected_variables_memory_handler,
     756                [('n1', 'value'), ('n3', 'value')],
     757            )
     758            self.assertEqual(
     759                collected_variables_temporary_handler,
     760                [('n1', 'value'), ('n3', 'value')],
     761            )
     762
    662763
    663764@skipIf(connection.vendor == 'sqlite'
    664765        and connection.settings_dict['NAME'] in ('', ':memory:'),
Back to Top