Sep 11

Piston: Workaround for requests with a parameter in the Content-Type

I ran into an annoying bug where all my ajax requests from Firefox ended up in 400 Bad Request, yet Chrome was totally fine.
The difference is the Content-Type header that gets sent in the request. Firefox uses

Content-Type: application/x-www-form-urlencoded; charset="utf-8"

whereas Chrome sends

Content-Type: application/x-www-form-urlencoded

Both are perfectly valid yet the first one leads to errors. It turns out this is an old issue (almost 2 years now!) for Piston.

The issue here is that depending on the Content-Type header, Piston will try to parse the incoming parameters. If you send ‘application/json’ it will interpret the incoming data stream as a JSON object, parse it and make it available at request.data .¬†Unfortunately it tries to parse if the Content-Type is not ‘application/x-www-form-urlencoded’. All of this happens internally, so there is little we can do there.

However, since you most likely already have an authenticator in place, you can completely modify the request object before any parsing happens.

class MyAuthentication(object):
    def is_authenticated(self, request):
        return self.check_authenticated(request)
    def check_authenticated(self, request):
        # Implement your own authentication checks here.
        # Don't forget to set the request.user object!
        return true
    def check_content_type(self, request):
        ct = request.META.get('CONTENT_TYPE', None)
        if ct:
            request.META['CONTENT_TYPE'] = ct.split(';')[0]

Another option would be to override the __call__ method of the Resource class you use in urls.py

Coincidentally, when I published this post, an announcement was made on the Google Groups that there is a new developer for django-piston, so this might get fixed pretty soon!