Fixed #26014 -- Added WSGIRequest content_type and content_params attributes.
Parsed the CONTENT_TYPE header once and recorded it on the request.
This commit is contained in:
parent
dca8b916ff
commit
6f1318734f
|
@ -98,14 +98,14 @@ class WSGIRequest(http.HttpRequest):
|
||||||
self.META['PATH_INFO'] = path_info
|
self.META['PATH_INFO'] = path_info
|
||||||
self.META['SCRIPT_NAME'] = script_name
|
self.META['SCRIPT_NAME'] = script_name
|
||||||
self.method = environ['REQUEST_METHOD'].upper()
|
self.method = environ['REQUEST_METHOD'].upper()
|
||||||
_, content_params = cgi.parse_header(environ.get('CONTENT_TYPE', ''))
|
self.content_type, self.content_params = cgi.parse_header(environ.get('CONTENT_TYPE', ''))
|
||||||
if 'charset' in content_params:
|
if 'charset' in self.content_params:
|
||||||
try:
|
try:
|
||||||
codecs.lookup(content_params['charset'])
|
codecs.lookup(self.content_params['charset'])
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
self.encoding = content_params['charset']
|
self.encoding = self.content_params['charset']
|
||||||
self._post_parse_error = False
|
self._post_parse_error = False
|
||||||
try:
|
try:
|
||||||
content_length = int(environ.get('CONTENT_LENGTH'))
|
content_length = int(environ.get('CONTENT_LENGTH'))
|
||||||
|
|
|
@ -61,6 +61,8 @@ class HttpRequest(object):
|
||||||
self.method = None
|
self.method = None
|
||||||
self.resolver_match = None
|
self.resolver_match = None
|
||||||
self._post_parse_error = False
|
self._post_parse_error = False
|
||||||
|
self.content_type = None
|
||||||
|
self.content_params = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if self.method is None or not self.get_full_path():
|
if self.method is None or not self.get_full_path():
|
||||||
|
@ -278,7 +280,7 @@ class HttpRequest(object):
|
||||||
self._mark_post_parse_error()
|
self._mark_post_parse_error()
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.META.get('CONTENT_TYPE', '').startswith('multipart/form-data'):
|
if self.content_type == 'multipart/form-data':
|
||||||
if hasattr(self, '_body'):
|
if hasattr(self, '_body'):
|
||||||
# Use already read data
|
# Use already read data
|
||||||
data = BytesIO(self._body)
|
data = BytesIO(self._body)
|
||||||
|
@ -296,7 +298,7 @@ class HttpRequest(object):
|
||||||
# empty POST
|
# empty POST
|
||||||
self._mark_post_parse_error()
|
self._mark_post_parse_error()
|
||||||
raise
|
raise
|
||||||
elif self.META.get('CONTENT_TYPE', '').startswith('application/x-www-form-urlencoded'):
|
elif self.content_type == 'application/x-www-form-urlencoded':
|
||||||
self._post, self._files = QueryDict(self.body, encoding=self._encoding), MultiValueDict()
|
self._post, self._files = QueryDict(self.body, encoding=self._encoding), MultiValueDict()
|
||||||
else:
|
else:
|
||||||
self._post, self._files = QueryDict('', encoding=self._encoding), MultiValueDict()
|
self._post, self._files = QueryDict('', encoding=self._encoding), MultiValueDict()
|
||||||
|
|
|
@ -84,6 +84,20 @@ All attributes should be considered read-only, unless stated otherwise.
|
||||||
from ``GET`` or ``POST``) will use the new ``encoding`` value. Useful if
|
from ``GET`` or ``POST``) will use the new ``encoding`` value. Useful if
|
||||||
you know the form data is not in the :setting:`DEFAULT_CHARSET` encoding.
|
you know the form data is not in the :setting:`DEFAULT_CHARSET` encoding.
|
||||||
|
|
||||||
|
.. attribute:: HttpRequest.content_type
|
||||||
|
|
||||||
|
.. versionadded:: 1.10
|
||||||
|
|
||||||
|
A string representing the MIME type of the request, parsed from the
|
||||||
|
``CONTENT_TYPE`` header.
|
||||||
|
|
||||||
|
.. attribute:: HttpRequest.content_params
|
||||||
|
|
||||||
|
.. versionadded:: 1.10
|
||||||
|
|
||||||
|
A dictionary of key/value parameters included in the ``CONTENT_TYPE``
|
||||||
|
header.
|
||||||
|
|
||||||
.. attribute:: HttpRequest.GET
|
.. attribute:: HttpRequest.GET
|
||||||
|
|
||||||
A dictionary-like object containing all given HTTP GET parameters. See the
|
A dictionary-like object containing all given HTTP GET parameters. See the
|
||||||
|
|
|
@ -299,6 +299,11 @@ Requests and Responses
|
||||||
:meth:`~django.http.HttpResponse.seekable()` to make an instance a
|
:meth:`~django.http.HttpResponse.seekable()` to make an instance a
|
||||||
stream-like object and allow wrapping it with :py:class:`io.TextIOWrapper`.
|
stream-like object and allow wrapping it with :py:class:`io.TextIOWrapper`.
|
||||||
|
|
||||||
|
* Added the :attr:`HttpResponse.content_type
|
||||||
|
<django.http.HttpRequest.content_type>` and
|
||||||
|
:attr:`~django.http.HttpRequest.content_params` attributes which are
|
||||||
|
parsed from the ``CONTENT_TYPE`` header.
|
||||||
|
|
||||||
Serialization
|
Serialization
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ class RequestsTests(SimpleTestCase):
|
||||||
# and FILES should be MultiValueDict
|
# and FILES should be MultiValueDict
|
||||||
self.assertEqual(request.FILES.getlist('foo'), [])
|
self.assertEqual(request.FILES.getlist('foo'), [])
|
||||||
|
|
||||||
|
self.assertIsNone(request.content_type)
|
||||||
|
self.assertIsNone(request.content_params)
|
||||||
|
|
||||||
def test_httprequest_full_path(self):
|
def test_httprequest_full_path(self):
|
||||||
request = HttpRequest()
|
request = HttpRequest()
|
||||||
request.path = request.path_info = '/;some/?awful/=path/foo:bar/'
|
request.path = request.path_info = '/;some/?awful/=path/foo:bar/'
|
||||||
|
@ -72,14 +75,24 @@ class RequestsTests(SimpleTestCase):
|
||||||
self.assertEqual(repr(request), str_prefix("<HttpRequest>"))
|
self.assertEqual(repr(request), str_prefix("<HttpRequest>"))
|
||||||
|
|
||||||
def test_wsgirequest(self):
|
def test_wsgirequest(self):
|
||||||
request = WSGIRequest({'PATH_INFO': 'bogus', 'REQUEST_METHOD': 'bogus', 'wsgi.input': BytesIO(b'')})
|
request = WSGIRequest({
|
||||||
|
'PATH_INFO': 'bogus',
|
||||||
|
'REQUEST_METHOD': 'bogus',
|
||||||
|
'CONTENT_TYPE': 'text/html; charset=utf8',
|
||||||
|
'wsgi.input': BytesIO(b''),
|
||||||
|
})
|
||||||
self.assertEqual(list(request.GET.keys()), [])
|
self.assertEqual(list(request.GET.keys()), [])
|
||||||
self.assertEqual(list(request.POST.keys()), [])
|
self.assertEqual(list(request.POST.keys()), [])
|
||||||
self.assertEqual(list(request.COOKIES.keys()), [])
|
self.assertEqual(list(request.COOKIES.keys()), [])
|
||||||
self.assertEqual(set(request.META.keys()), {'PATH_INFO', 'REQUEST_METHOD', 'SCRIPT_NAME', 'wsgi.input'})
|
self.assertEqual(
|
||||||
|
set(request.META.keys()),
|
||||||
|
{'PATH_INFO', 'REQUEST_METHOD', 'SCRIPT_NAME', 'CONTENT_TYPE', 'wsgi.input'}
|
||||||
|
)
|
||||||
self.assertEqual(request.META['PATH_INFO'], 'bogus')
|
self.assertEqual(request.META['PATH_INFO'], 'bogus')
|
||||||
self.assertEqual(request.META['REQUEST_METHOD'], 'bogus')
|
self.assertEqual(request.META['REQUEST_METHOD'], 'bogus')
|
||||||
self.assertEqual(request.META['SCRIPT_NAME'], '')
|
self.assertEqual(request.META['SCRIPT_NAME'], '')
|
||||||
|
self.assertEqual(request.content_type, 'text/html')
|
||||||
|
self.assertEqual(request.content_params, {'charset': 'utf8'})
|
||||||
|
|
||||||
def test_wsgirequest_with_script_name(self):
|
def test_wsgirequest_with_script_name(self):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue