Commit 91b33659 by spiq

fix for PUT files

parent 30fd23d7
...@@ -24,6 +24,27 @@ class StandardContentMixin(ContentMixin): ...@@ -24,6 +24,27 @@ class StandardContentMixin(ContentMixin):
return None return None
return (request.META.get('CONTENT_TYPE', None), request.raw_post_data) return (request.META.get('CONTENT_TYPE', None), request.raw_post_data)
from django.core.files.base import File
class SocketFile(File):
# Only forward access is allowed
def __init__(self, socket, size):
super(SocketFile, self).__init__(socket)
self._size = int(size)
self._pos = 0
def read(self, num_bytes=None):
if num_bytes is None:
num_bytes = self._size - self._pos
else:
num_bytes = min(num_bytes, self._size - self._pos)
self._pos += num_bytes
return self.file.read(num_bytes)
def tell(self):
return self._pos
def seek(self, position):
pass
class OverloadedContentMixin(ContentMixin): class OverloadedContentMixin(ContentMixin):
"""HTTP request content behaviour that also allows arbitrary content to be tunneled in form data.""" """HTTP request content behaviour that also allows arbitrary content to be tunneled in form data."""
...@@ -39,7 +60,7 @@ class OverloadedContentMixin(ContentMixin): ...@@ -39,7 +60,7 @@ class OverloadedContentMixin(ContentMixin):
Note that content_type may be None if it is unset.""" Note that content_type may be None if it is unset."""
if not request.META.get('CONTENT_LENGTH', None) and not request.META.get('TRANSFER_ENCODING', None): if not request.META.get('CONTENT_LENGTH', None) and not request.META.get('TRANSFER_ENCODING', None):
return None return None
content_type = request.META.get('CONTENT_TYPE', None) content_type = request.META.get('CONTENT_TYPE', None)
if (request.method == 'POST' and self.CONTENT_PARAM and if (request.method == 'POST' and self.CONTENT_PARAM and
...@@ -51,5 +72,13 @@ class OverloadedContentMixin(ContentMixin): ...@@ -51,5 +72,13 @@ class OverloadedContentMixin(ContentMixin):
content_type = request.POST.get(self.CONTENTTYPE_PARAM, None) content_type = request.POST.get(self.CONTENTTYPE_PARAM, None)
return (content_type, request.POST[self.CONTENT_PARAM]) return (content_type, request.POST[self.CONTENT_PARAM])
elif request.method == 'PUT':
return (content_type, request.raw_post_data) f = SocketFile(request.environ['wsgi.input'], request.META['CONTENT_LENGTH'])
\ No newline at end of file returned = (content_type, f.read())
return returned
#try:
# f.close()
#except Exception as e:
# print 'exception', e
else:
return (content_type, request.raw_post_data)
from StringIO import StringIO
from django.http.multipartparser import MultiPartParser as DjangoMPParser
from djangorestframework.response import ResponseException from djangorestframework.response import ResponseException
from djangorestframework import status from djangorestframework import status
...@@ -6,6 +10,10 @@ try: ...@@ -6,6 +10,10 @@ try:
except ImportError: except ImportError:
import simplejson as json import simplejson as json
try:
from urlparse import parse_qs
except ImportError:
from cgi import parse_qs
class ParserMixin(object): class ParserMixin(object):
parsers = () parsers = ()
...@@ -75,50 +83,57 @@ class FormParser(BaseParser): ...@@ -75,50 +83,57 @@ class FormParser(BaseParser):
"""The default parser for form data. """The default parser for form data.
Return a dict containing a single value for each non-reserved parameter. Return a dict containing a single value for each non-reserved parameter.
""" """
# TODO: not good, because posted/put lists are flattened !!!
media_type = 'application/x-www-form-urlencoded' media_type = 'application/x-www-form-urlencoded'
def parse(self, input): def parse(self, input):
# The FormParser doesn't parse the input as other parsers would, since Django's already done the
# form parsing for us. We build the content object from the request directly.
request = self.resource.request request = self.resource.request
if request.method == 'PUT': if request.method == 'PUT':
# Fix from piston to force Django to give PUT requests the same data = parse_qs(input)
# form processing that POST requests get... # Flattening the parsed query data
# for key, val in data.items():
# Bug fix: if _load_post_and_files has already been called, for data[key] = val[0]
# example by middleware accessing request.POST, the below code to
# pretend the request is a POST instead of a PUT will be too late if request.method == 'POST':
# to make a difference. Also calling _load_post_and_files will result # Django has already done the form parsing for us.
# in the following exception: data = dict(request.POST.items())
# AttributeError: You cannot set the upload handlers after the upload has been processed.
# The fix is to check for the presence of the _post field which is set
# the first time _load_post_and_files is called (both by wsgi.py and
# modpython.py). If it's set, the request has to be 'reset' to redo
# the query value parsing in POST mode.
if hasattr(request, '_post'):
del request._post
del request._files
try:
request.method = "POST"
request._load_post_and_files()
request.method = "PUT"
except AttributeError:
request.META['REQUEST_METHOD'] = 'POST'
request._load_post_and_files()
request.META['REQUEST_METHOD'] = 'PUT'
# Strip any parameters that we are treating as reserved # Strip any parameters that we are treating as reserved
data = {} for key in data:
for (key, val) in request.POST.items(): if key in self.resource.RESERVED_FORM_PARAMS:
if key not in self.resource.RESERVED_FORM_PARAMS: data.pop(key)
data[key] = val
return data return data
# TODO: Allow parsers to specify multiple media_types # TODO: Allow parsers to specify multiple media_types
class MultipartParser(FormParser): class MultipartParser(FormParser):
media_type = 'multipart/form-data' media_type = 'multipart/form-data'
def parse(self, input):
request = self.resource.request
if request.method == 'PUT':
upload_handlers = request._get_upload_handlers()
django_mpp = DjangoMPParser(request.META, StringIO(input), upload_handlers)
data, files = django_mpp.parse()
data = dict(data)
files = dict(files)
if request.method == 'POST':
# Django has already done the form parsing for us.
data = dict(request.POST)
files = dict(request.FILES)
# Flattening, then merging the POSTED/PUT data/files
for key, val in dict(data).items():
data[key] = val[0]
for key, val in dict(files).items():
files[key] = val[0].read()
data.update(files)
# Strip any parameters that we are treating as reserved
for key in data:
if key in self.resource.RESERVED_FORM_PARAMS:
data.pop(key)
return data
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment