From 6dfd68b5ec2436205dad8a795bad50bec38c150c Mon Sep 17 00:00:00 2001 From: Charan Rathore <180254320+charan-rathore@users.noreply.github.com> Date: Sun, 18 Oct 2026 12:13:39 +0530 Subject: [PATCH] Format JSON bodies regardless of MIME type casing JSONFormatter matched the content type case-sensitively, so a response declared as APPLICATION/JSON (or any other casing) was printed raw instead of being pretty-printed. Lower-case the MIME string before matching, as RFC 9110 media types are case-insensitive. Fixes #1958. Signed-off-by: Charan Rathore <180254320+charan-rathore@users.noreply.github.com> --- httpie/output/formatters/json.py | 1 + tests/test_output.py | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/httpie/output/formatters/json.py b/httpie/output/formatters/json.py index bc6151e42f..a3a1aad9d6 100644 --- a/httpie/output/formatters/json.py +++ b/httpie/output/formatters/json.py @@ -10,6 +10,7 @@ def __init__(self, **kwargs): self.enabled = self.format_options['json']['format'] def format_body(self, body: str, mime: str) -> str: + mime = mime.lower() maybe_json = [ 'json', 'javascript', diff --git a/tests/test_output.py b/tests/test_output.py index 2242177dbc..ed713bafcb 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -629,3 +629,41 @@ def test_response_mime_overwrite_incorrect(): # The provided Content-Type is simply ignored, and so no formatting is done. r = http('--response-mime=incorrect/type', DUMMY_URL) assert XML_DATA_RAW in r + + +class TestJSONFormatterMIME: + """JSONFormatter must match the body MIME type case-insensitively (#1958).""" + + @staticmethod + def make_formatter(): + from httpie.output.formatters.json import JSONFormatter + return JSONFormatter( + format_options={'json': {'format': True, 'sort_keys': True, 'indent': 4}}, + explicit_json=False, + ) + + @pytest.mark.parametrize( + 'mime', + [ + 'application/json', + 'APPLICATION/JSON', + 'Application/Problem+JSON; charset=UTF-8', + ] + ) + def test_format_body_matches_mime_case_insensitively(self, mime: str): + formatted = self.make_formatter().format_body('{"a": 1}', mime) + assert '\n' in formatted + assert json.loads(formatted) == {'a': 1} + + @pytest.mark.parametrize( + 'mime', + [ + 'text/plain', + 'application/xml', + ] + ) + def test_format_body_case_parity_for_non_json(self, mime: str): + # An upper-cased MIME type behaves exactly like its lower-case form. + body = '{"a": 1}' + formatter = self.make_formatter() + assert formatter.format_body(body, mime.upper()) == formatter.format_body(body, mime)