Login

HttpMethodsMiddleware

Author:
hawkeye
Posted:
April 12, 2007
Language:
Python
Version:
.96
Score:
7 (after 7 ratings)

This middleware allows developers to "fake" browser support for HTTP methods. Even though most modern browsers only support GET and POST, the HTTP standard defines others. In the context of REST, PUT and DELETE are used for client interaction with the server.

For forms with a PUT or DELETE method, this middleware will change them to go through POST, and will include an invisible field called "method_middleware_transform" that carries the originally intended method.

So, <form method="PUT" ...>...</form> More or less becomes <form method="POST" ...><input type=hidden name="method_middleware_transform" value="PUT"></form> (with a few other minor HTML modifications)

The process is completely transparent to the developer... you never have to deal with the fact that browsers don't support the standard methods.

One caveat is that server interaction via XMLHttpRequest (AJAX) requires special attention... this middleware won't properly setup your XMLHttpRequest to take advantage of this functionality.

This is a combination of the work of Jesse Lovelace and the Django CSRF middleware.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import re
import itertools

_HTML_TYPES = ('text/html', 'application/xhtml+xml')    

_SUPPORTED_TRANSFORMS = ['PUT', 'DELETE']

_FORM_RE = re.compile(r'((<form\W[^>]*\bmethod=(\'|"|))(%s)((\'|"|)\b[^>]*>))' % '|'.join(_SUPPORTED_TRANSFORMS), re.IGNORECASE)

_MIDDLEWARE_KEY = 'method_middleware_transform'
 
class HttpMethodsMiddleware(object):
    def process_request(self, request):
        if request.POST and request.POST.has_key(_MIDDLEWARE_KEY):
            if request.POST[_MIDDLEWARE_KEY].upper() in _SUPPORTED_TRANSFORMS:
                request.method = request.POST[_MIDDLEWARE_KEY]
        return None
           
    def process_response(self, request, response):
        if response['Content-Type'].split(';')[0] in _HTML_TYPES:
            # ensure we don't add the 'id' attribute twice (HTML validity)
            idattributes = itertools.chain(("id='" + _MIDDLEWARE_KEY + "'",), 
                                            itertools.repeat(''))
            def add_transform_field(match):
                """Returns the matched <form> tag with a modified method and
                the added <input> element"""
                return match.group(2) + "POST" + match.group(5) + \
                "<div style='display:none;'>" + \
                "<input type='hidden' " + idattributes.next() + \
                " name='" + _MIDDLEWARE_KEY + "' value='" + \
                match.group(4).upper() + "' /></div>"

            # Modify any POST forms
            response.content = _FORM_RE.sub(add_transform_field, response.content)
        return response

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

peplin (on April 20, 2011):

Be aware that this snippet as is can expose your application to CSRF attacks. Django's CSRF checks will always occur after this middleware is run, and it currently only checks POST requests.

I've made some updates for our version of this snippet here (with more comments): https://github.com/bueda/django-comrade/commit/de4d38b0c503908f11d5d73a60e3beef4735997c

#

Please login first before commenting.