mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-08 06:14:47 +03:00
Merge f8854f11f3
into 69fb34b0db
This commit is contained in:
commit
ec823c5230
|
@ -86,7 +86,7 @@ def clone_request(request, method):
|
||||||
ret._full_data = request._full_data
|
ret._full_data = request._full_data
|
||||||
ret._content_type = request._content_type
|
ret._content_type = request._content_type
|
||||||
ret._stream = request._stream
|
ret._stream = request._stream
|
||||||
ret.method = method
|
ret._method = method
|
||||||
if hasattr(request, '_user'):
|
if hasattr(request, '_user'):
|
||||||
ret._user = request._user
|
ret._user = request._user
|
||||||
if hasattr(request, '_auth'):
|
if hasattr(request, '_auth'):
|
||||||
|
@ -129,6 +129,11 @@ class Request(object):
|
||||||
- authentication_classes(list/tuple). The authentications used to try
|
- authentication_classes(list/tuple). The authentications used to try
|
||||||
authenticating the request's user.
|
authenticating the request's user.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
_METHOD_PARAM = api_settings.FORM_METHOD_OVERRIDE
|
||||||
|
_CONTENT_PARAM = api_settings.FORM_CONTENT_OVERRIDE
|
||||||
|
_CONTENTTYPE_PARAM = api_settings.FORM_CONTENTTYPE_OVERRIDE
|
||||||
|
|
||||||
def __init__(self, request, parsers=None, authenticators=None,
|
def __init__(self, request, parsers=None, authenticators=None,
|
||||||
negotiator=None, parser_context=None):
|
negotiator=None, parser_context=None):
|
||||||
self._request = request
|
self._request = request
|
||||||
|
@ -139,6 +144,7 @@ class Request(object):
|
||||||
self._data = Empty
|
self._data = Empty
|
||||||
self._files = Empty
|
self._files = Empty
|
||||||
self._full_data = Empty
|
self._full_data = Empty
|
||||||
|
self._method = Empty
|
||||||
self._content_type = Empty
|
self._content_type = Empty
|
||||||
self._stream = Empty
|
self._stream = Empty
|
||||||
|
|
||||||
|
@ -156,6 +162,18 @@ class Request(object):
|
||||||
def _default_negotiator(self):
|
def _default_negotiator(self):
|
||||||
return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS()
|
return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def method(self):
|
||||||
|
"""
|
||||||
|
Returns the HTTP method.
|
||||||
|
|
||||||
|
This allows the `method` to be overridden by using a hidden `form`
|
||||||
|
field on a form POST request.
|
||||||
|
"""
|
||||||
|
if not _hasattr(self, '_method'):
|
||||||
|
self._load_method_and_content_type()
|
||||||
|
return self._method
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def content_type(self):
|
def content_type(self):
|
||||||
meta = self._request.META
|
meta = self._request.META
|
||||||
|
@ -247,6 +265,23 @@ class Request(object):
|
||||||
else:
|
else:
|
||||||
self._full_data = self._data
|
self._full_data = self._data
|
||||||
|
|
||||||
|
def _load_method_and_content_type(self):
|
||||||
|
"""
|
||||||
|
Sets the method and content_type, and then check if they've
|
||||||
|
been overridden.
|
||||||
|
"""
|
||||||
|
self._content_type = self.META.get('HTTP_CONTENT_TYPE',
|
||||||
|
self.META.get('CONTENT_TYPE', ''))
|
||||||
|
|
||||||
|
self._perform_form_overloading()
|
||||||
|
|
||||||
|
if not _hasattr(self, '_method'):
|
||||||
|
self._method = self._request.method
|
||||||
|
|
||||||
|
# Allow X-HTTP-METHOD-OVERRIDE header
|
||||||
|
if 'HTTP_X_HTTP_METHOD_OVERRIDE' in self.META:
|
||||||
|
self._method = self.META['HTTP_X_HTTP_METHOD_OVERRIDE'].upper()
|
||||||
|
|
||||||
def _load_stream(self):
|
def _load_stream(self):
|
||||||
"""
|
"""
|
||||||
Return the content body of the request, as a stream.
|
Return the content body of the request, as a stream.
|
||||||
|
@ -254,7 +289,9 @@ class Request(object):
|
||||||
meta = self._request.META
|
meta = self._request.META
|
||||||
try:
|
try:
|
||||||
content_length = int(
|
content_length = int(
|
||||||
meta.get('CONTENT_LENGTH', meta.get('HTTP_CONTENT_LENGTH', 0))
|
meta.get(
|
||||||
|
'CONTENT_LENGTH', meta.get('HTTP_CONTENT_LENGTH')
|
||||||
|
)
|
||||||
)
|
)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
content_length = 0
|
content_length = 0
|
||||||
|
@ -266,6 +303,50 @@ class Request(object):
|
||||||
else:
|
else:
|
||||||
self._stream = six.BytesIO(self.raw_post_data)
|
self._stream = six.BytesIO(self.raw_post_data)
|
||||||
|
|
||||||
|
def _perform_form_overloading(self):
|
||||||
|
"""
|
||||||
|
If this is a form POST request, then we need to check if the method and
|
||||||
|
content/content_type have been overridden by setting them in hidden
|
||||||
|
form fields or not.
|
||||||
|
"""
|
||||||
|
|
||||||
|
USE_FORM_OVERLOADING = (
|
||||||
|
self._METHOD_PARAM or
|
||||||
|
(self._CONTENT_PARAM and self._CONTENTTYPE_PARAM)
|
||||||
|
)
|
||||||
|
|
||||||
|
# We only need to use form overloading on form POST requests.
|
||||||
|
if (
|
||||||
|
self._request.method != 'POST' or
|
||||||
|
not USE_FORM_OVERLOADING or
|
||||||
|
not is_form_media_type(self._content_type)
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
# At this point we're committed to parsing the request as form data.
|
||||||
|
self._data = self._request.POST
|
||||||
|
self._files = self._request.FILES
|
||||||
|
self._full_data = self._data.copy()
|
||||||
|
self._full_data.update(self._files)
|
||||||
|
|
||||||
|
# Method overloading - change the method and remove the param from the content.
|
||||||
|
if (
|
||||||
|
self._METHOD_PARAM and
|
||||||
|
self._METHOD_PARAM in self._data
|
||||||
|
):
|
||||||
|
self._method = self._data[self._METHOD_PARAM].upper()
|
||||||
|
|
||||||
|
# Content overloading - modify the content type, and force re-parse.
|
||||||
|
if (
|
||||||
|
self._CONTENT_PARAM and
|
||||||
|
self._CONTENTTYPE_PARAM and
|
||||||
|
self._CONTENT_PARAM in self._data and
|
||||||
|
self._CONTENTTYPE_PARAM in self._data
|
||||||
|
):
|
||||||
|
self._content_type = self._data[self._CONTENTTYPE_PARAM]
|
||||||
|
self._stream = six.BytesIO(self._data[self._CONTENT_PARAM].encode(self.parser_context['encoding']))
|
||||||
|
self._data, self._files, self._full_data = (Empty, Empty, Empty)
|
||||||
|
|
||||||
def _parse(self):
|
def _parse(self):
|
||||||
"""
|
"""
|
||||||
Parse the request content, returning a two-tuple of (data, files)
|
Parse the request content, returning a two-tuple of (data, files)
|
||||||
|
|
|
@ -92,6 +92,9 @@ DEFAULTS = {
|
||||||
'rest_framework.renderers.JSONRenderer'
|
'rest_framework.renderers.JSONRenderer'
|
||||||
),
|
),
|
||||||
'TEST_REQUEST_DEFAULT_FORMAT': 'multipart',
|
'TEST_REQUEST_DEFAULT_FORMAT': 'multipart',
|
||||||
|
'FORM_METHOD_OVERRIDE': '_method',
|
||||||
|
'FORM_CONTENT_OVERRIDE': '_content',
|
||||||
|
'FORM_CONTENTTYPE_OVERRIDE': '_content_type',
|
||||||
|
|
||||||
# Hyperlink settings
|
# Hyperlink settings
|
||||||
'URL_FORMAT_OVERRIDE': 'format',
|
'URL_FORMAT_OVERRIDE': 'format',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user