srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2026-05-15 19:48:00 +0200
committersrdusr <[email protected]>2026-05-15 19:48:00 +0200
commitdd1621c0077e079e0693f16fe83f17d50338216e (patch)
tree411a06d723a16aff1077d5d3e724680436aac85a /cmd
parentd7d50ae9902d69b2e52d446684b5ab01a5ecab1e (diff)
downloadmitmux-dd1621c0077e079e0693f16fe83f17d50338216e.tar.gz
mitmux-dd1621c0077e079e0693f16fe83f17d50338216e.zip
Stop mislabeling truncated captures as "exact"
internal/proxy/tee.go's teeConn silently drops bytes past maxCaptureBytes (10 MiB) but callers unconditionally marked the result "exact" anyway. Confirmed live: proxying a 15 MiB response worked correctly end-to-end (the client got the full, real 15 MiB - proxying itself is unbounded, only storage is capped), but the stored history entry was exactly 10485760 bytes with response_exact=1 still set. For a tool whose core value proposition is "raw bytes are the source of truth," a silently truncated capture presented as complete could hide the very evidence a smuggling or parser-differential investigation is looking for in the tail of a large body - and give false confidence that it isn't there. teeConn.Take() now returns (data, truncated) instead of just data; truncated is true whenever a Read had to drop bytes because the buffer was already at cap. Every caller (proxy.go's forward() on both the request and response side, repeat.go's sendRaw for Repeater/Intruder) now folds truncated into exact - a truncated capture is never marked exact - and additionally threads a distinct RequestTruncated/ ResponseTruncated bool through store.Entry, ipc.EntryDetail, and the TUI, since "truncated" and "reconstructed" (HTTP/2, which never had wire-exact bytes to begin with) are different situations worth telling apart: a truncated capture is still real wire bytes, just incomplete, not a synthesized reconstruction. The detail/repeater views now show "truncated (hit capture size limit)" specifically rather than lumping it in with "reconstructed", which would have implied more transformation happened than actually did. Schema: history gains request_truncated/response_truncated columns via the same ALTER-TABLE-and-ignore-duplicate-column pattern already used for source/flagged, so existing databases upgrade in place. Verified live: a target server returning a 15 MiB body (over the 10 MiB cap) proxied through cleanly - full body reached the client - while the stored entry shows length=10485760, response_exact=0, response_truncated=1 (previously would have shown response_exact=1); the TUI's Detail view correctly displays "Response (10485760 bytes, truncated (hit capture size limit))" instead of "exact". go build/vet/gofmt/test/mod tidy all clean.
Diffstat (limited to 'cmd')
-rw-r--r--cmd/mitmux/main.go21
1 files changed, 15 insertions, 6 deletions
diff --git a/cmd/mitmux/main.go b/cmd/mitmux/main.go
index 75f4410..83e59cd 100644
--- a/cmd/mitmux/main.go
+++ b/cmd/mitmux/main.go
@@ -1532,8 +1532,8 @@ func (m *model) detailView() string {
b.WriteString(titleStyle.Render(title))
b.WriteString("\n")
- reqLabel := fmt.Sprintf("Request (%d bytes%s)", len(m.detail.RequestRaw), exactSuffix(m.detail.RequestExact))
- respLabel := fmt.Sprintf("Response (%d bytes%s)", len(m.detail.ResponseRaw), exactSuffix(m.detail.ResponseExact))
+ reqLabel := fmt.Sprintf("Request (%d bytes%s)", len(m.detail.RequestRaw), exactSuffix(m.detail.RequestExact, m.detail.RequestTruncated))
+ respLabel := fmt.Sprintf("Response (%d bytes%s)", len(m.detail.ResponseRaw), exactSuffix(m.detail.ResponseExact, m.detail.ResponseTruncated))
if m.prettyMode {
respLabel += " [pretty]"
}
@@ -1580,7 +1580,7 @@ func (m *model) repeaterView() string {
reqLabel := "Request (editable)"
respLabel := "Response"
if t.result != nil {
- respLabel = fmt.Sprintf("Response (%d bytes%s)", len(t.result.ResponseRaw), exactSuffix(t.result.ResponseExact))
+ respLabel = fmt.Sprintf("Response (%d bytes%s)", len(t.result.ResponseRaw), exactSuffix(t.result.ResponseExact, t.result.ResponseTruncated))
}
if t.focus == focusRequest {
b.WriteString(tabActive.Render(reqLabel))
@@ -1783,11 +1783,20 @@ func intrudeRowsFor(rs []ipc.IntrudeResultMsg) []table.Row {
return rows
}
-func exactSuffix(exact bool) string {
- if exact {
+// exactSuffix labels a capture's trust level. truncated is a distinct
+// state from a plain "reconstructed" (HTTP/2, which never had wire-exact
+// bytes to begin with): these ARE real wire bytes, just cut short by
+// hitting the capture size cap - telling them apart matters for a tool
+// whose value proposition is "raw bytes are the source of truth."
+func exactSuffix(exact, truncated bool) string {
+ switch {
+ case exact:
return ", exact"
+ case truncated:
+ return ", truncated (hit capture size limit)"
+ default:
+ return ", reconstructed"
}
- return ", reconstructed"
}
// detailContent is what actually gets shown in the detail viewport: