-
Notifications
You must be signed in to change notification settings - Fork 24
Description
When session_csrf is used in conjunction with piston to protect a PUT request, things break:
File "/home/scjody/pwbank/src/hg/web-banking/lib/python2.6/site-packages/django/views/decorators/vary.py", line 19, in inner_func
response = func(*args, **kwargs)
File "/home/scjody/pwbank/src/hg/web-banking/src/trustcentric/resource.py", line 101, in __call__
coerce_put_post(request)
File "/home/scjody/pwbank/src/hg/web-banking/lib/python2.6/site-packages/piston/utils.py", line 144, in coerce_put_post
request._load_post_and_files()
File "/home/scjody/pwbank/src/hg/web-banking/lib/python2.6/site-packages/django/http/__init__.py", line 360, in _load_post_and_files
self._post, self._files = self.parse_file_upload(self.META, data)
File "/home/scjody/pwbank/src/hg/web-banking/lib/python2.6/site-packages/django/http/__init__.py", line 317, in parse_file_upload
warning = "You cannot alter upload handlers after the upload has been processed."
File "/home/scjody/pwbank/src/hg/web-banking/lib/python2.6/site-packages/django/http/__init__.py", line 302, in _set_upload_handlers
raise AttributeError("You cannot set the upload handlers after the upload has been processed.")
AttributeError: You cannot set the upload handlers after the upload has been processed.
This is because of the way Piston works around Django's lack of PUT support: it sets request.method to POST, calls request._load_post_and_files(), and then sets request.method back to PUT. This works fine unless session_csrf is being used, in which case _load_post_and_files() fails with the error above.
I can't think of a good way to fix Piston. A fairly gross way to work around it in session_csrf is to do:
--- a/session_csrf/__init__.py
+++ b/session_csrf/__init__.py
@@ -87,7 +87,9 @@ class CsrfMiddleware(object):
# Try to get the token from the POST and fall back to looking at the
# X-CSRFTOKEN header.
- user_token = request.POST.get('csrfmiddlewaretoken', '')
+ user_token = ''
+ if request.method == 'POST':
+ user_token = request.POST.get('csrfmiddlewaretoken', '')
if user_token == '':
user_token = request.META.get('HTTP_X_CSRFTOKEN', '')This will prevent any request that sets a "csrfmiddlewaretoken" field in a PUT rather than using an X-CSRFToken header from passing CSRF checks, but that wasn't going to work anyway with the current session_csrf (it only checks POST, which will be empty.)
Given that Django's PUT support is lacking anyway - anyone doing a PUT is probably using Piston or Tastypie, which uses _load_post_and_files too - is this the best we can do, or can someone think of a better way?
Should I submit a pull request with this fix given that it's better than what session_csrf currently does?