Skip to content

Commit 37877c1

Browse files
committed
🔧 relax strictness around Response.json(...) that checked Content-Type prior to decoding
We may review that behavior in a future major version.
1 parent ee4f225 commit 37877c1

File tree

2 files changed

+19
-5
lines changed

2 files changed

+19
-5
lines changed

HISTORY.md

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

4+
3.12.3 (2025-01-28)
5+
-------------------
6+
7+
**Changed**
8+
- Relaxed strict compliance on JSON parsing. We brought strict compliance into Niquests, a response
9+
must explicitly set `Content-Type: application/json` or alike prior to attempt parsing the JSON string.
10+
We decided to relax that constraint as old and bad-behaving server may send JSON with missing or broken Content-Type.
11+
412
3.12.2 (2025-01-22)
513
-------------------
614

src/niquests/models.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -1444,8 +1444,8 @@ def json(self, **kwargs: typing.Any) -> typing.Any:
14441444
contain valid json or if content-type is not about json.
14451445
"""
14461446

1447-
if not self.content or "json" not in self.headers.get("content-type", "").lower():
1448-
raise RequestsJSONDecodeError("response content is not JSON", self.text or "", 0)
1447+
if not self.content:
1448+
raise RequestsJSONDecodeError("response content is not JSON", "", 0)
14491449

14501450
if not self.encoding:
14511451
# No encoding set. JSON RFC 4627 section 3 states we should expect
@@ -1467,10 +1467,13 @@ def json(self, **kwargs: typing.Any) -> typing.Any:
14671467
).best()
14681468

14691469
if encoding_guess is not None:
1470+
self.encoding = encoding_guess.encoding
14701471
try:
14711472
return _json.loads(str(encoding_guess), **kwargs)
14721473
except _json.JSONDecodeError as e:
14731474
raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
1475+
else:
1476+
self.encoding = "utf-8" # try Unicode anyway[...]
14741477

14751478
plain_content = self.text
14761479

@@ -1813,8 +1816,8 @@ async def text(self) -> str | None: # type: ignore[override]
18131816
async def json(self, **kwargs: typing.Any) -> typing.Any: # type: ignore[override]
18141817
content = await self.content
18151818

1816-
if not content or "json" not in self.headers.get("content-type", "").lower():
1817-
raise RequestsJSONDecodeError("response content is not JSON", await self.text or "", 0)
1819+
if not content:
1820+
raise RequestsJSONDecodeError("response content is not JSON", "", 0)
18181821

18191822
if not self.encoding:
18201823
# No encoding set. JSON RFC 4627 section 3 states we should expect
@@ -1836,15 +1839,18 @@ async def json(self, **kwargs: typing.Any) -> typing.Any: # type: ignore[overri
18361839
).best()
18371840

18381841
if encoding_guess is not None:
1842+
self.encoding = encoding_guess.encoding
18391843
try:
18401844
return _json.loads(str(encoding_guess), **kwargs)
18411845
except _json.JSONDecodeError as e:
18421846
raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
1847+
else:
1848+
self.encoding = "utf-8"
18431849

18441850
plain_content = await self.text
18451851

18461852
if plain_content is None:
1847-
raise RequestsJSONDecodeError("response cannot lead to decodable JSON", "", 0)
1853+
raise RequestsJSONDecodeError("response cannot lead to unserializable JSON", "", 0)
18481854

18491855
try:
18501856
return _json.loads(plain_content, **kwargs)

0 commit comments

Comments
 (0)