Django csrf token invalid after modifying request

904 Views Asked by At

I am trying to do POST tunneling on my Django website. What I am basically trying to do is to "enable" PUT and DELETE. So, now I am struggling with DELETE. In my template.html I have the following:

    <form action="/photos/{{ photo.id }}/" method="POST" > 
    {% csrf_token %}
        <button type="submit" class="btn btn-link" >Delete photo</button> 
        <input id="override" type="hidden" name="_method" value="DELETE"/>
    </form> 

In this way, I am trying to delete a photo by providing additional attribute "_method" to my request.POST.

I have written a middleware class that should be in charge of replacing "POST" with "DELETE" in my request:

class HTMLTunneling(object):

        def process_request(self, request):
            if request.POST.has_key('_method'):
                http_method = request.POST['_method']

                if http_method.lower() == 'put':
                    request.method = 'PUT'
                    request.META['REQUEST_METHOD'] = 'PUT'
                    request.PUT = QueryDict(request.body)

                if http_method.lower() == 'delete':
                    request.method = 'DELETE'
                    request.META['REQUEST_METHOD'] = 'DELETE'
                    request.DELETE = QueryDict(request.body)

            return None

But, django keeps throwing

Forbidden (403)
CSRF verification failed. Request aborted

every time I click my delete button. If I remove the middleware, it works. If I do anything that will disable the delete functionality, it works. I don't understand. Can anyone assist me with this?

Here is the view that is supposed to be processing this request:

@login_required
def handle_image(request, image_id):
    """
    Main handler for an image. Checks what kind of a request came and redirects
    traffic according to it.
    """
    if request.method == 'GET':
        return show_image(request, image_id)

    elif request.method == 'DELETE':
        return delete_image(request, image_id)

    elif request.method == 'PUT':
        # print("Inside put")
        # update image with a like or comment
        if request.PUT.has_key('publ'):
            return privacy(request, image_id)

        if request.PUT.has_key('like'):
            return like_image(request, image_id)

        if request.PUT.has_key('comm'):
            return comment(request, image_id)

It actually just invokes the corresponding views. For example, the privacy view looks like this:

@login_required
def privacy(request, image_id):
    try:
        # user = CustomUser.objects.get(pk=user_id)
        photo = Photo.objects.get(pk=image_id)
    except:
        raise Http404  

    accessor = request.user.customuser
    if accessor != photo.owner:
        return HttpResponseForbidden("Forbidden")

    if request.PUT['publ'] == "true":
        photo.public = True
        photo.save()
    elif request.PUT['publ'] == "false":
        photo.public = False
        photo.save()

    c = image_context(photo, accessor)  
    return render(request, 'photos/view_image.html', c)

It just sets the image attribute to public or private. I did this by following advice from here and here. I don't have any AJAX stuff of course, only plain html.

0

There are 0 best solutions below