srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/internal/ipc
AgeCommit message (Collapse)AuthorFilesLines
2024-08-29Repeater: raw-byte send/resendsrdusr2-18/+64
Implements build-order step 4, the feature the plan calls out as used daily. internal/proxy/repeat.go adds Server.Repeat(scheme, host, raw): dials fresh (HTTP/1.1-only - raw edited text has no equivalent in HTTP/2's binary framing), writes raw exactly as given with no framing correction or header injection, and captures the exact response bytes. This is deliberately separate from forward()'s parsed-*http.Request path since Repeater's entire point is letting a malformed/edited request reach the wire unmodified. Repeater sends are recorded to the same history table as proxy traffic (added a "source" column: "proxy" vs "repeater") so they show up in the unified history view and the live subscribe stream, not a separate silo. internal/ipc gains a "repeat" request/response pair; cmd/mitmuxd wires proxy.Server into ipc.NewServer via a small Repeater interface so the daemon keeps owning all network I/O and the TUI stays a thin client. cmd/mitmux gains a repeater view (bubbles/textarea for the editable raw request, a read-only viewport for the response), reachable with 'r' from either the list or detail view, ctrl+r to send. One real bug found via testing: bubbles/textarea only understands LF, but HTTP/1.1 requires CRLF, so loading raw bytes straight into it split each line in two on render. Fixed by normalizing CRLF<->LF at the editor boundary only (load: strip \r; send: restore it) - documented as a narrow, known trade-off for bodies with their own embedded LF line breaks, which is the cost of being able to edit raw HTTP as text at all. Verified live: edited and sent a plain-HTTP repeater request (confirmed in SQLite that the edit - including an intentional extra blank line from imprecise cursor navigation during testing - went out completely unmodified, which is the correct behavior: mitmux must never "fix" what the user typed), and sent an HTTPS repeater request against a freshly captured entry, both getting real 200 responses with exact response bytes back.
2024-02-14History view: SQLite storage, daemon/TUI split over Unix socketsrdusr2-0/+262
Implements build-order step 3. Adds: - internal/store: SQLite (WAL, single-writer) history table, raw request/response blobs plus metadata for the list view. - internal/proxy: request/response capture wired into forward(). HTTP/1.1 legs are captured byte-exact via a teeConn that records wire bytes as they're read, taken right after the message is fully drained (so no manual re-reading/replaying is needed - RoundTrip's own streaming does the draining). HTTP/2 legs (no meaningful "raw bytes" of their own - multiplexed, HPACK-compressed framing) are reconstructed instead, and marked as such in storage. - internal/ipc: JSON-over-Unix-socket protocol between mitmuxd (owns the proxy and the DB) and any client - list/get for queries, subscribe for a live push stream of newly captured entries. Keeps the proxy engine independent of the UI, per the architecture sketch. - cmd/mitmux: Bubble Tea TUI - a live-updating history table and a request/response detail view with raw bytes. Two real bugs surfaced during testing and got fixed before commit: 1. http.Transport's HTTP/2 auto-dispatch does a literal *tls.Conn type assertion on the dialed connection; wrapping it in a capturing teeConn broke that silently, and HTTP/2 framing got parsed as HTTP/1.1 text. Fixed by dropping http.Transport for the upstream leg entirely in favor of an explicit per-protocol round trip (see PLAN.md stack note). 2. singleConnListener wrapped the client teeConn *inside* a closeSignalConn, so ConnContext's type assertion for it silently failed and HTTP/1.1 client-side capture never activated. Fixed the wrap order; verified via direct SQLite inspection that request_exact flips back to 1 and the stored bytes are genuinely wire-exact (preserved chunked-encoding framing, original header casing/order). Verified live: plain HTTP, HTTPS H1.1, HTTPS H2, and a POST with a body, checked against the raw stored bytes directly in SQLite; IPC list/get/ subscribe against a throwaway client; and the TUI driven end-to-end in a tmux session (list, detail view, tab between request/response, live update on a new request while sitting on the list).