Opened 10 years ago

Closed 9 years ago

Last modified 9 years ago

#14182 closed (fixed)

CsrfViewMiddleware makes modification of the upload handlers impossible

Reported by: dc Owned by: Luke Plant
Component: File uploads/storage Version: 1.2
Severity: Keywords: csrf upload_handlers
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


CsrfViewMiddleware accesses request.POST and makes modification of the upload handlers on a per-request basis impossible.

Currently it's impossible to simultaneously use per-request upload handlers and csrf protection. At least this must be documented.

See also:

Steps to reproduce

Put attached in PYTHONPATH.

Start new default django project:

$ startproject project

Modify project/

urlpatterns = patterns('',
    (r'^upload/$', 'upload_test.upload_file'),

Open browser at /upload/ and submit form.

Actual Results

AttributeError at /upload/

You cannot alter upload handlers after the upload has been processed.

Expected Results

Normal form handling in upload_file() view.

Attachments (1) (1.3 KB) - added by dc 10 years ago.
Test file

Download all attachments as: .zip

Change History (5)

Changed 10 years ago by dc

Attachment: added

Test file

comment:1 Changed 10 years ago by Luke Plant

Owner: changed from nobody to Luke Plant
Status: newassigned

Hmmm, tricky, I can't think of a nice way to get this to work automatically. If you use csrf_exempt can you work around this? Something like this:

from django.views.decorators.csrf import csrf_exempt, csrf_protect  ## Added

@csrf_exempt                         ## Added
def upload_file(request):
    request.upload_handlers.insert(0, DummyUploadHandler())
    return upload_file_real(request) ## Added

@csrf_protect                        ## Added
def upload_file_real(request)        ## Added

    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            template = Template('''
                <!DOCTYPE html>
            context = RequestContext(request)
            return HttpResponse(template.render(context))
        form = UploadFileForm()

    template = Template('''
        <!DOCTYPE html>
        <form action="." enctype="multipart/form-data" method="post">
            {% csrf_token %}
            {{ form }}
            <input type="submit">
    context = RequestContext(request, {'form': form})
    return HttpResponse(template.render(context))

Does that work? If it does, would you mind coming up with a patch for the documentation?

comment:2 Changed 9 years ago by laurikari

Replying to lukeplant:

Using @csrf_exempt and @csrf_protect work, insofar that it's possible to add a custom upload handler that way.

However, something worth noting is that if you do this, your upload handlers will be receiving file data _before_ the CSRF checks are done. It might be worth mentioning this also in Django documentation - upload handlers receive data which hasn't been checked for CSRF yet.

comment:3 Changed 9 years ago by Luke Plant

Resolution: fixed
Status: assignedclosed

(In [13960]) Fixed #14182 - documented how to modify upload handlers when using CsrfViewMiddleware

Thanks to dc for the report.

comment:4 Changed 9 years ago by Luke Plant

(In [13961]) [1.2.X] Fixed #14182 - documented how to modify upload handlers when using CsrfViewMiddleware

Thanks to dc for the report.

Backport of [13960] from trunk

Note: See TracTickets for help on using tickets.
Back to Top