) -> 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(
+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):
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)