Skip to content

Commit 6347b4b

Browse files
lindycodersloria
authored andcommitted
Handle decoding errors like json decode errors (#428)
* Handle decoding errors like json decode errors When receiving a post containing non utf8 data with a Application/Json content-type, the decoding fails. This should be treated as an incorrect JSON payload and return a 400. fixes #427 * Update changelog and AUTHORS
1 parent fb8ff11 commit 6347b4b

7 files changed

+52
-2
lines changed

AUTHORS.rst

+1
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ Contributors (chronological)
4040
* Xiaoyu Lee <https://github.com/lee3164>
4141
* Jonathan Angelo <https://github.com/jangelo>
4242
* @zhenhua32 <https://github.com/zhenhua32>
43+
* Martin Roy <https://github.com/lindycoder>

CHANGELOG.rst

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
Changelog
22
---------
33

4+
5.5.2 (unreleased)
5+
******************
6+
7+
Bug fixes:
8+
9+
* Handle ``UnicodeDecodeError`` when parsing JSON payloads (:issue:`427`).
10+
Thanks :user:`lindycoder` for the catch and patch.
11+
412
5.5.1 (2019-09-15)
513
******************
614

src/webargs/aiohttpparser.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ async def parse_json(self, req: Request, name: str, field: Field) -> typing.Any:
102102
return core.missing
103103
else:
104104
return self.handle_invalid_json_error(e, req)
105+
except UnicodeDecodeError as e:
106+
return self.handle_invalid_json_error(e, req)
107+
105108
self._cache["json"] = json_data
106109
return core.get_value(json_data, name, field, allow_many_nested=True)
107110

@@ -164,7 +167,11 @@ def handle_error(
164167
)
165168

166169
def handle_invalid_json_error(
167-
self, error: json.JSONDecodeError, req: Request, *args, **kwargs
170+
self,
171+
error: typing.Union[json.JSONDecodeError, UnicodeDecodeError],
172+
req: Request,
173+
*args,
174+
**kwargs
168175
) -> "typing.NoReturn":
169176
error_class = exception_map[400]
170177
messages = {"json": ["Invalid JSON body."]}

src/webargs/bottleparser.py

+3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ def parse_json(self, req, name, field):
4747
return core.missing
4848
else:
4949
return self.handle_invalid_json_error(e, req)
50+
except UnicodeDecodeError as e:
51+
return self.handle_invalid_json_error(e, req)
52+
5053
if json_data is None:
5154
return core.missing
5255
return core.get_value(json_data, name, field, allow_many_nested=True)

src/webargs/core.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,14 @@ def get_value(data, name, field, allow_many_nested=False):
112112

113113
def parse_json(s, encoding="utf-8"):
114114
if isinstance(s, bytes):
115-
s = s.decode(encoding)
115+
try:
116+
s = s.decode(encoding)
117+
except UnicodeDecodeError as e:
118+
raise json.JSONDecodeError(
119+
"Bytes decoding error : {}".format(e.reason),
120+
doc=str(e.object),
121+
pos=e.start,
122+
)
116123
return json.loads(s)
117124

118125

src/webargs/testing.py

+12
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,18 @@ def test_parse_json_with_nonascii_chars(self, testapp):
117117
text = u"øˆƒ£ºº∆ƒˆ∆"
118118
assert testapp.post_json("/echo", {"name": text}).json == {"name": text}
119119

120+
# https://github.com/marshmallow-code/webargs/issues/427
121+
def test_parse_json_with_nonutf8_chars(self, testapp):
122+
res = testapp.post(
123+
"/echo",
124+
b"\xfe",
125+
headers={"Accept": "application/json", "Content-Type": "application/json"},
126+
expect_errors=True,
127+
)
128+
129+
assert res.status_code == 400
130+
assert res.json == {"json": ["Invalid JSON body."]}
131+
120132
def test_validation_error_returns_422_response(self, testapp):
121133
res = testapp.post("/echo", {"name": "b"}, expect_errors=True)
122134
assert res.status_code == 422

tests/test_falconparser.py

+12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ def test_parse_files(self, testapp):
1616
def test_use_args_hook(self, testapp):
1717
assert testapp.get("/echo_use_args_hook?name=Fred").json == {"name": "Fred"}
1818

19+
# https://github.com/marshmallow-code/webargs/issues/427
20+
def test_parse_json_with_nonutf8_chars(self, testapp):
21+
res = testapp.post(
22+
"/echo",
23+
b"\xfe",
24+
headers={"Accept": "application/json", "Content-Type": "application/json"},
25+
expect_errors=True,
26+
)
27+
28+
assert res.status_code == 400
29+
assert res.json["errors"] == {"json": ["Invalid JSON body."]}
30+
1931
# https://github.com/sloria/webargs/issues/329
2032
def test_invalid_json(self, testapp):
2133
res = testapp.post(

0 commit comments

Comments
 (0)