mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-11 04:07:39 +03:00
fix for PUT files
This commit is contained in:
parent
30fd23d7f5
commit
91b33659b5
|
@ -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):
|
||||||
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):
|
||||||
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'])
|
||||||
|
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)
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
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:
|
||||||
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):
|
||||||
"""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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user