Commit 0a38bc9d by Tom Christie

Deal with parser encodings properly

parent b052c92a
...@@ -5,6 +5,7 @@ They give us a generic way of being able to handle various media types ...@@ -5,6 +5,7 @@ They give us a generic way of being able to handle various media types
on the request, such as form content or json encoded data. on the request, such as form content or json encoded data.
""" """
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings
from django.http import QueryDict from django.http import QueryDict
from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser
from django.http.multipartparser import MultiPartParserError from django.http.multipartparser import MultiPartParserError
...@@ -55,8 +56,11 @@ class JSONParser(BaseParser): ...@@ -55,8 +56,11 @@ class JSONParser(BaseParser):
`data` will be an object which is the parsed content of the response. `data` will be an object which is the parsed content of the response.
`files` will always be `None`. `files` will always be `None`.
""" """
parser_context = parser_context or {}
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
try: try:
data = stream.read().decode('iso-8859-1') data = stream.read().decode(encoding)
return json.loads(data) return json.loads(data)
except ValueError as exc: except ValueError as exc:
raise ParseError('JSON parse error - %s' % six.text_type(exc)) raise ParseError('JSON parse error - %s' % six.text_type(exc))
...@@ -76,8 +80,11 @@ class YAMLParser(BaseParser): ...@@ -76,8 +80,11 @@ class YAMLParser(BaseParser):
`data` will be an object which is the parsed content of the response. `data` will be an object which is the parsed content of the response.
`files` will always be `None`. `files` will always be `None`.
""" """
parser_context = parser_context or {}
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
try: try:
data = stream.read().decode('iso-8859-1') data = stream.read().decode(encoding)
return yaml.safe_load(data) return yaml.safe_load(data)
except (ValueError, yaml.parser.ParserError) as exc: except (ValueError, yaml.parser.ParserError) as exc:
raise ParseError('YAML parse error - %s' % six.u(exc)) raise ParseError('YAML parse error - %s' % six.u(exc))
...@@ -97,7 +104,9 @@ class FormParser(BaseParser): ...@@ -97,7 +104,9 @@ class FormParser(BaseParser):
`data` will be a :class:`QueryDict` containing all the form parameters. `data` will be a :class:`QueryDict` containing all the form parameters.
`files` will always be :const:`None`. `files` will always be :const:`None`.
""" """
data = QueryDict(stream.read()) parser_context = parser_context or {}
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
data = QueryDict(stream.read(), encoding=encoding)
return data return data
...@@ -117,11 +126,12 @@ class MultiPartParser(BaseParser): ...@@ -117,11 +126,12 @@ class MultiPartParser(BaseParser):
""" """
parser_context = parser_context or {} parser_context = parser_context or {}
request = parser_context['request'] request = parser_context['request']
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
meta = request.META meta = request.META
upload_handlers = request.upload_handlers upload_handlers = request.upload_handlers
try: try:
parser = DjangoMultiPartParser(meta, stream, upload_handlers) parser = DjangoMultiPartParser(meta, stream, upload_handlers, encoding)
data, files = parser.parse() data, files = parser.parse()
return DataAndFiles(data, files) return DataAndFiles(data, files)
except MultiPartParserError as exc: except MultiPartParserError as exc:
...@@ -136,8 +146,11 @@ class XMLParser(BaseParser): ...@@ -136,8 +146,11 @@ class XMLParser(BaseParser):
media_type = 'application/xml' media_type = 'application/xml'
def parse(self, stream, media_type=None, parser_context=None): def parse(self, stream, media_type=None, parser_context=None):
parser_context = parser_context or {}
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
parser = ET.XMLParser(encoding=encoding)
try: try:
tree = ET.parse(stream) tree = ET.parse(stream, parser=parser)
except (ExpatError, ETParseError, ValueError) as exc: except (ExpatError, ETParseError, ValueError) as exc:
raise ParseError('XML parse error - %s' % six.u(exc)) raise ParseError('XML parse error - %s' % six.u(exc))
data = self._xml_convert(tree.getroot()) data = self._xml_convert(tree.getroot())
......
...@@ -10,6 +10,7 @@ The wrapped request then offers a richer API, in particular : ...@@ -10,6 +10,7 @@ The wrapped request then offers a richer API, in particular :
- form overloading of HTTP method, content type and content - form overloading of HTTP method, content type and content
""" """
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings
from django.http.multipartparser import parse_header from django.http.multipartparser import parse_header
from rest_framework import HTTP_HEADER_ENCODING from rest_framework import HTTP_HEADER_ENCODING
from rest_framework import exceptions from rest_framework import exceptions
...@@ -92,6 +93,7 @@ class Request(object): ...@@ -92,6 +93,7 @@ class Request(object):
if self.parser_context is None: if self.parser_context is None:
self.parser_context = {} self.parser_context = {}
self.parser_context['request'] = self self.parser_context['request'] = self
self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET
def _default_negotiator(self): def _default_negotiator(self):
return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS() return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS()
......
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