]> git.feebdaed.xyz Git - 0xmirror/mitmproxy.git/commitdiff
Console: Show query parameters for empty-body requests (#7923)
authorMatteo Luppi <100372313+lups2000@users.noreply.github.com>
Mon, 3 Nov 2025 16:57:24 +0000 (17:57 +0100)
committerGitHub <noreply@github.com>
Mon, 3 Nov 2025 16:57:24 +0000 (17:57 +0100)
* show query parameters for empty-body requests

* [autofix.ci] apply automated fixes

* update changelog

* fix PR number

* access directly the query attribute

* [autofix.ci] apply automated fixes

* nits

* coverage++

* [autofix.ci] apply automated fixes

* coverage ++

* [autofix.ci] apply automated fixes

* review changes

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
CHANGELOG.md
mitmproxy/tools/console/flowview.py
test/mitmproxy/tools/console/test_flowview.py

index 0cdc8b56e3c9e4b2495bf07cd66c745feb6c16f7..9072baa83d8ca0332d5c8e78f1cb0bfc833e71ee 100644 (file)
@@ -13,6 +13,8 @@
   ([#7933](https://github.com/mitmproxy/mitmproxy/pull/7933), @caiquejjx, @mhils)
 - Fix various issues in infer_content_encoding
   ([#7928](https://github.com/mitmproxy/mitmproxy/pull/7928), @xu-cheng)
+- Show query parameters for empty-body requests in the mitmproxy console.
+  ([#7923](https://github.com/mitmproxy/mitmproxy/pull/7923), @lups2000)
 
 ## 15 October 2025: mitmproxy 12.2.0
 
index ec942ece31b6f621030ee1eb0106877747483978..fda5b5a506e8d407a830316c6f56aebf33ba3da6 100644 (file)
@@ -312,32 +312,36 @@ class FlowDetails(tabs.Tabs):
     ) -> tuple[str, list[urwid.Text]]:
         if message.raw_content is None:
             return "", [urwid.Text([("error", "[content missing]")])]
-        elif message.raw_content == b"":
+
+        if message.raw_content == b"":
             if isinstance(message, http.Request):
-                return "", [urwid.Text("No request content")]
+                query = getattr(message, "query", "")
+                if not query:
+                    # No body and no query params
+                    return "", [urwid.Text("No request content")]
+                # else: there are query params -> fall through to render them
             else:
                 return "", [urwid.Text("No content")]
+
+        full = self.master.commands.execute(
+            "view.settings.getval @focus fullcontents false"
+        )
+
+        if full == "true":
+            limit = sys.maxsize
         else:
-            full = self.master.commands.execute(
-                "view.settings.getval @focus fullcontents false"
-            )
-            if full == "true":
-                limit = sys.maxsize
-            else:
-                limit = ctx.options.content_view_lines_cutoff
+            limit = ctx.options.content_view_lines_cutoff
 
-            flow_modify_cache_invalidation = hash(
-                (
-                    message.raw_content,
-                    message.headers.fields,
-                    getattr(message, "path", None),
-                )
-            )
-            # we need to pass the message off-band because it's not hashable
-            self._get_content_view_message = message
-            return self._get_content_view(
-                viewmode, limit, flow_modify_cache_invalidation
+        flow_modify_cache_invalidation = hash(
+            (
+                message.raw_content,
+                message.headers.fields,
+                getattr(message, "path", None),
             )
+        )
+        # we need to pass the message off-band because it's not hashable
+        self._get_content_view_message = message
+        return self._get_content_view(viewmode, limit, flow_modify_cache_invalidation)
 
     @lru_cache(maxsize=200)
     def _get_content_view(
index c8287baad181f51c9d775b1d43571a668adbfb9e..191f5af0bb704a48d2d8508ff53c0bddc115d0cc 100644 (file)
@@ -1,5 +1,9 @@
+import sys
+from unittest import mock
+
 from mitmproxy import http
 from mitmproxy.test import tflow
+from mitmproxy.tools.console.flowview import FlowDetails
 
 
 async def test_flowview(console):
@@ -31,3 +35,60 @@ async def test_edit(console, monkeypatch, caplog):
     console.type(':console.edit.focus "request-body (MsgPack)"<enter><enter>')
     assert "hello: false" in console.screen_contents()
     assert f.request.content == MSGPACK_WITH_FALSE
+
+
+async def test_content_missing_returns_error(console):
+    # message.raw_content is None -> expect "[content missing]" error text
+    f_missing = tflow.tflow(
+        req=http.Request.make("GET", "http://example.com", b"initial"),
+    )
+    f_missing.request.raw_content = None
+
+    await console.load_flow(f_missing)
+
+    fd = FlowDetails(console)
+
+    title, txt_objs = fd.content_view("default", f_missing.request)
+    assert title == ""
+
+    first_text = txt_objs[0].get_text()[0]
+    assert "[content missing]" == first_text
+
+
+async def test_empty_content_request_and_response(console):
+    fd = FlowDetails(console)
+
+    # 1) Request with empty body and no query -> "No request content"
+    f_req_empty = tflow.tflow(
+        req=http.Request.make("GET", "http://example.com", b""),
+    )
+    f_req_empty.request.raw_content = b""
+    await console.load_flow(f_req_empty)
+    title_req, txt_objs_req = fd.content_view("default", f_req_empty.request)
+    assert title_req == ""
+    req_text = txt_objs_req[0].get_text()[0]
+    assert "No request content" == req_text
+
+    # 2) Response with empty body -> "No content"
+    f_resp_empty = tflow.tflow(
+        req=http.Request.make("GET", "http://example.com", b""),
+        resp=http.Response.make(200, b"", {}),
+    )
+    f_resp_empty.response.raw_content = b""
+    await console.load_flow(f_resp_empty)
+    title_resp, txt_objs_resp = fd.content_view("default", f_resp_empty.response)
+    assert title_resp == ""
+    resp_text = txt_objs_resp[0].get_text()[0]
+    assert "No content" == resp_text
+
+
+async def test_content_view_fullcontents_true_uses_unlimited_limit(console):
+    f = tflow.tflow(req=http.Request.make("POST", "http://example.com", b"non-empty"))
+    await console.load_flow(f)
+
+    fd = FlowDetails(console)
+
+    console.commands.execute("view.settings.setval @focus fullcontents true")
+    fd._get_content_view = mock.MagicMock()
+    fd.content_view("default", f.request)
+    fd._get_content_view.assert_called_with("default", sys.maxsize, mock.ANY)